﻿using com.yoozoo.gta;
using nTools.PrefabPainter;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization.Json;
using System.Text;
using Unity.Mathematics;
using UnityEditor;
using UnityEngine;
using WorldMap;
using WorldMapBase;
using WorldMapNew;
using WorldMapTools;
using Yoozoo.UI.YGUI;
using static WorldMapTools.GeneralMap;

namespace Tools.Maptools.Editor
{
    public class AreaData
    {
        public int mapSize;
        public int mapAreaSize;
        public MapAreaInfo[] mapInfos;
        public MapOverSeaInfo[] overSeaInfos;
    }
    public class MapAreaInfo
    {
        public int index; // 从0开始递增
        public int mapAreaId; // 所属地图区域id
        public int resLevel;// 资源等级
        public int cityLevel;// 主城出生优先级
        public int monsterLevel;// 野怪等级
        public int fogId;// 迷雾所属奇观id
        public int smuggleLevel;// 走私车队等级
    }

    public class MapOverSeaInfo
    {
        public int[] index; // 从1开始递增
        public int type; // 副本类型 1(银行副本)
        public int uid;// 副本uid 从1开始
    }
    
    public struct mapPointInfo
    {
        public int localId;
        public Vector2 localPos;
        public int type;
    };
    [Serializable]
    public class MapData
    {
        //地图宽（默认1200）
        public int mapWidth = 1200;
        //地图高（默认1200）
        public int mapHeight = 1200;
        //格子宽（默认30）
        public int areaWidth = 30;
        //格子高（默认30）
        public int areaHeight = 30;
        //所有area
        public List<MapAreaData> areas = new List<MapAreaData>();
  
    }
    [Serializable]
    public class MapAreaData
    {
        //格子id,30*30的那个一维下标
        public int areaId = 0;
        //区域等级（先保留如果能和之前的资源等级合并就用）
        public int resLevel = 0;
        //该area下的所有小格子
        public List<MapCellData> cells = new List<MapCellData>();
        public List<MapSpecial> specials; // 新增点位配置
    }
    
    public class MapSpecial
    {
        public int cellId = 0; //小格子整个地图中排序id 唯一
        public List<int> specialCfgs; // 对应cellId特殊配置 -海岛 走私车队、堡垒 具体配置方法由策划和后端商定
    }
    
    [Serializable]
    public class MapCellData
    {
        public int cellId = 0; //小格子整个地图中排序id 唯一
        public float x = 0; //x坐标
        public float z = 0; //z坐标
        public int type = 0; //格子类型（1.出生点 2.资源点 3.出生点+资源点）
    }

    public class MapLineDatas
    {
        public List<MapLineData> lines;
    }

    public class MapLineData
    {
        public List<MapNodeData> nodes;
    }

    public class MapNodeData
    {
        public Vector3 node;
        public List<Vector3> point;
    }

    // 奇观路线结构体
    public class WonderLineDatas
    {
        public List<WonderLineData> lines; // 奇观间路点数据
        public List<WonderPointData> points; // 奇观衔接点数据
    }

    public class WonderLineData
    {
        public int startWonderId; // 起始奇观id
        public int startCrossIdx;// 起始衔接点idx
        public int endWonderId; // 结束奇观id
        public int endCrossIdx;// 结束衔接点idx
        public float wonderLineTime;// 奇观路线时间 毫秒
        public List<Vector3> points; // 路点
    }

    public class WonderPointData
    {
        public int id; // 奇观id
        public List<Vector3> points; // 衔接点 左下角 逆时针
    }

    public class CreateMapEditorWindow : EditorWindow
    {
        #region 编辑器相关
        Vector2 m_scrollPosition = new Vector2(0, 0);
        List<UnityEngine.Object> m_Icons;
        static string[] TAB = new string[] { "地图块编辑", "地图编辑", "其他" };
        TextEditor m_te = new TextEditor();
        enum ETAB
        {
            ChunckEditor,       //地图块编辑
            MapEditor,          //地图编辑
            Other,              //其他
        }
        GUIContent[] GUIArr;
        ETAB m_Tab = ETAB.ChunckEditor;
        static private Vector2 m_winSize = new Vector2(800, 750);
        GUIStyle m_tabBtnStyle;
        GUIStyle m_tabTextSytel;

        //序列化对象
        protected SerializedObject _serializedObject;
        //序列化属性
        protected SerializedProperty _assetLstProperty;

        bool DevelopmentToolsChunckElment = false;

        #endregion

        #region 大地图相关
        private Vector2 scrollPos;

        bool DevelopmentToolsDFoldOut = false;

        bool DevelopmentToolsEFoldOut = false;

        bool DevelopmentToolsFFoldOut = false;

        bool DevelopmentToolsPointAdornFoldOut = false;

        bool DevelopmentToolReplaceFoldOut = false;

        bool DevelopmentToolAllRoadFoldOut = false;

        bool DevelopmentToolLineFoldOut = false;

        public Vector2 m_GlobalScroll = Vector2.zero;

        private GeneralMap _generalMap;//

        private WorldMapData _worldMap;
        private WorldMapData _worldAllMap;
        private WorldMapData _worldMap1;

        private WorldMapData _chunckData;
        private GameObject _worldChunck;
        private Dictionary<int, Color> mapChunckEditorColor = new Dictionary<int, Color>(); // 各地图块编辑器对应颜色

        private WorldMapData _worldMapObstruct;
        private GameObject mapObstructRoot;
        private GameObject _editorMapObstructRoot;

        MapLineDatas _mapLines;
        GameObject _mapLineRoot;
        int curLineIdx;
        int curNodeIdx;
        GameObject _curLineObj;
        GameObject _curNodeObj;

        GameObject _wonderCrossRoot;
        GameObject _startWonderCross;
        GameObject _endWonderCross;
        GameObject _editorWonderLine;
        GameObject _editorOverSeaShapeRoot;
        float _editorWonderLineTime;// 当前选中奇观路线时间
        
        GameObject _mapTrainLineRoot;
        GameObject _wonderCenterRoot;
        GameObject _startWonderCenter;
        GameObject _endWonderCenter;
        GameObject _editorTrainLine;
        // ======================================================================================================================
        #region 地图区域信息相关
        private GameObject mapAreaEditorRoot;
        
        enum mapAreaEditorType // 地图区域编辑类型
        { 
            E_AREA = 1, // 关卡
            E_RESLEVEL = 2,// 资源等级
            E_CITY = 3,// 主城出生等级
            E_MONSTER = 4,// 野怪等级
            E_FOGID = 5,// 迷雾所属奇观id
            E_Monster_Smuggle_Level = 6,// 走私车队等级
        }
        private Dictionary<mapAreaEditorType, Dictionary<int, int>> mapAreaInfos = new Dictionary<mapAreaEditorType, Dictionary<int, int>>();// <mapAreaEditorType,<idx,int>>
        private Dictionary<int, MapFogRunDta> mapFogInfos = new Dictionary<int, MapFogRunDta>();
        private Dictionary<mapAreaEditorType, bool> mapAreaInfoEditorState = new Dictionary<mapAreaEditorType, bool>// 各类型当前编辑状态
        {
            [mapAreaEditorType.E_AREA] = false,
            [mapAreaEditorType.E_RESLEVEL] = false,
            [mapAreaEditorType.E_CITY] = false,
            [mapAreaEditorType.E_MONSTER] = false,
            [mapAreaEditorType.E_FOGID] = false,
            [mapAreaEditorType.E_Monster_Smuggle_Level] = false,
        };
        private Dictionary<mapAreaEditorType, string> mapAreaInfoEditorName = new Dictionary<mapAreaEditorType, string>// 各类型名字
        {
            [mapAreaEditorType.E_AREA] = "关卡ID",
            [mapAreaEditorType.E_RESLEVEL] = "资源等级",
            [mapAreaEditorType.E_CITY] = "主城出生等级",
            [mapAreaEditorType.E_MONSTER] = "野怪等级",
            [mapAreaEditorType.E_FOGID] = "迷雾所属奇观ID",
            [mapAreaEditorType.E_Monster_Smuggle_Level] = "走私车队等级",
        };
        private Vector2 mapAreaEditorStart = new Vector2(-1, -1);// 编辑起始点
        private Dictionary<mapAreaEditorType, int> mapAreaInfoEditorLevel = new Dictionary<mapAreaEditorType, int>// 各类型当前编辑等级
        {
            [mapAreaEditorType.E_AREA] = 1,
            [mapAreaEditorType.E_RESLEVEL] = 1,
            [mapAreaEditorType.E_CITY] = 1,
            [mapAreaEditorType.E_MONSTER] = 1,
            [mapAreaEditorType.E_FOGID] = 1,
            [mapAreaEditorType.E_Monster_Smuggle_Level] = 1,
        };
        private Dictionary<int, Color> mapResLevelColors = new Dictionary<int, Color>// 资源等级对应导出颜色
        {
            [0] = new Color(91.0f / 255f, 150.0f / 255f, 69.0f / 255f), // 河道的颜色
            [1] = new Color(187.0f / 255f,218.0f / 255f,175.0f / 255f),
            [2] = new Color(145.0f / 255f, 198.0f / 255f, 125.0f / 255f),
            [3] = new Color(107.0f / 255f, 170.0f / 255f, 82.0f / 255f),
            [4] = new Color(81.0f / 255f,146.0f / 255f, 55.0f / 255f),
            [5] = new Color(60.0f / 255f, 129.0f / 255f, 33.0f / 255f),
            [6] = new Color(39.0f / 255f, 107.0f / 255f, 12.0f / 255f),
        };
        private bool bMouseMove = false;
        private bool bMapAreaEditor = false;
        private Dictionary<mapAreaEditorType, List<Color>> mapAreaInfoEditorColor = new Dictionary<mapAreaEditorType, List<Color>>(); // 各类型当前编辑等级对应颜色
        bool bMapAreaEditorInit = false;

        // 迷雾编辑相关
        int MapFogOutSize = 1800;// 迷雾lod5尺寸
        int MapFogSize = 10;// 迷雾块粒度
        int MapFofLineNum = 180;//  迷雾块一行数量
        GameObject MapFogEditorRoot;
        Dictionary<int, GameObject> MapFogEditorObjs = new Dictionary<int, GameObject>();
        Dictionary<int, YText> MapFogEditorYTexts = new Dictionary<int, YText>();
        Dictionary<int, GameObject> MapFogOutEditorObjs = new Dictionary<int, GameObject>(); // 界外迷雾
        Dictionary<int, YText> MapFogOutEditorYTexts = new Dictionary<int, YText>(); // 界外迷雾
        List<GameObject> MapFogEditorPool = new List<GameObject>();
        #endregion
        // ======================================================================================================================
        #region 地图块出生点相关
        [SerializeField]
        protected List<UnityEngine.GameObject> mapChuncks = new List<UnityEngine.GameObject>();
        private bool bShowMapPoint = false;
        private GameObject mapPointRoot;
        private bool bShowOverSeaChunck = false;
        #endregion

        #region 地图块出生点装饰物相关

        private GameObject _pointAdornChunck;
        private PointAdornRoot _pointAdornRootScript;
        List<string> adornType = new List<string>()
        {
            "无","右上角","右下角","左下角","左上角","上边相连","右边相连","下边相连","左边相连","二级装饰物","出生点衔接车道"
        };
        private int _pointAdornType = 0;
        private GameObject _pointAdornObj;
        private GameObject _pointAdornModol;
        private GameObject _pointTagertObj;

        private GameObject _pointRoot;
        #endregion

        #region 地图块性能分级
        private Dictionary<GameObject, int> MapChunckLevelMap = new Dictionary<GameObject, int>();
        bool bMapChunckDebug = false; // 性能分级调试开关
        int MapChunckDebugLevel = 0;// 性能分级调试等级
        bool DevelopmentToolsHFoldOut = false;
        GameObject mapChunckLevelObj;
        private Dictionary<int, Color> mapChunckLevelColor = new Dictionary<int, Color>(); // 地图块各性能等级对应颜色
        WorldMapData mapChunckLevelData;
        #endregion

        #endregion

        #region 地图块相关

        enum ChunckElementType
        {
            E_Null = 0,
            E_City = 1,
            E_Res = 2,
            E_CityAndRes = 3,// 主城或者资源点
            E_Alliance = 4,// 联盟街区点
            E_Wonder = 5,// 奇观
            E_Checkpoint = 6,// 关卡
            E_RallyPoint = 7,//  联盟中立资源点
            E_RaderRpg = 8,// 雷达RPG功能建筑
            E_RaderRts = 9,// 雷达RTS功能建筑
            E_WonderPoint_1 = 10, // 奇观功能点 建筑
            E_WonderPoint_2 = 11, // 奇观功能点 增援队
            E_WonderPoint_3 = 12, // 奇观功能点 突击队
            E_StationPoint = 20,// 关卡通行点

            E_ActivityBuild = 21,// 活动建筑出生点
            E_Monster_Smuggle_0 = 22, // 走私车队 固定点(海外副本)
            E_Monster_Smuggle_1 = 23, // 走私车队 随机点(舍弃)
            E_TRANSFER_POINT = 24, //传送点(海外副本)
            E_BANK = 25, //银行(海外副本)
            E_WAR_CASTLE = 26, //战争城堡(海外副本)
            E_HIGH_BANK = 27, //高级城堡(海外副本)

            E_ISLAND_HEGEMONY_1 = 28,// 同盟对决-海岛争霸 点类型1
            E_ISLAND_HEGEMONY_2 = 29,// 同盟对决-海岛争霸 点类型2

            E_EditorResPoint = 100,// 编辑用资源点 -不会导出给服务器 只是客户端用来编辑的资源点
        }
        GameObject mapChunckRoot;       // 地图块根节点
        GameObject mapPlaneRoot;
        GameObject mapElement;          // 地图元素
        string s_mapElementSize = "2";  // 地图元素尺寸 string
        float mapElementSize = 2;       // 地图元素尺寸
        string chuckDataName = "";      // 地图数据名 必填
        ChunckElementType curType;
        GameObject chunckCenter;// 地图锚点 设置默认为15 15
        bool bSetPlaneType = false;
        bool bSetPointCfg = false;
        List<int> pointSpecialCfg = new List<int>();
        Dictionary<GameObject, string> pointSpecialCfgMap = new Dictionary<GameObject, string>();
        string savePath = "Assets/ResourcesAssets/World/mapdata/"; // 路径
        string savePointPath = "Assets/Editor/EditorCfg/MapData/"; // 点数据路径
        string panelModelPath = "Assets/Arts/World/sandtable/prefabs/chunckElemnt.prefab"; 
        string panelModel1Path = "Assets/Arts/World/sandtable/prefabs/chunckElemnt1.prefab"; 
        string artPanelModelPath = "Assets/Arts/World/sandtable/prefabs/{0}.prefab"; // 路径 
        string mapPointPrefabPath = "Assets/ResourcesAssets/World/prefabs/sandtable/other/mapPoint.prefab";
        string mapUnionPointPrefabPath = "Assets/ResourcesAssets/World/prefabs/sandtable/other/mapUnion.prefab";
        public List<mapPointInfo> pointInfos = new List<mapPointInfo>();
        public Dictionary<GameObject, mapPointInfo> pointInfoMap = new Dictionary<GameObject, mapPointInfo>();
        public Dictionary<GameObject, Material> pointTypeMap = new Dictionary<GameObject, Material>();

        List<List<Vector3>> mapEdgeLines = new List<List<Vector3>>(); // 虚线集合
        Dictionary<int, int> point_vertical = new Dictionary<int, int>(); // 竖线边界点集合 <起始点坐标idx,终点坐标idx>
        Dictionary<int, int> point_horizontal = new Dictionary<int, int>(); // 横线边界点集合 <起始点坐标idx,终点坐标idx>

        public Dictionary<int, Color> typeToColorMap = new Dictionary<int, Color>()
        {
            [0] = Color.gray,
            [1] = Color.yellow,
            [2] = Color.green,
            [3] = Color.yellow,
            [4] = Color.blue,
            [5] = new Color(0.6391867f, 0.1057316f, 0.8301887f),// 蛋黄
            [6] = Color.white,
            [7] = new Color(128 / 255, 0, 128 / 255),// 紫色
            [8] = new Color(0.78f, 0.67f, 1),// 蛋黄
            [9] = new Color(0.67f, 0.67f, 1),// shi黄
            [10] = new Color(0.080315f, 0.2358491f, 0.01668743f),
            [11] = new Color(0.1446053f, 0.4056604f, 0.04018334f),
            [12] = new Color(0.1965457f, 0.5660378f, 0.04538983f),
            [20] = new Color(1, 0.67f, 0.95f),// shi黄

            [21] = new Color(0.129361f, 0.2132973f, 0.5377358f),
            [22] = new Color(0.2042542f, 0.3344545f, 0.8490566f),
            [23] = Color.gray,
            [24] = Color.yellow,
            [25] = Color.blue,
            [26] = Color.red,
            [27] = Color.green,
            [28] = Color.green,
            [29] = Color.blue,


            [100] = Color.green,
        };

        public Dictionary<int, float> typeToSizeMap = new Dictionary<int, float>()
        {
            [0] = 1,
            [1] = 1,
            [2] = 1,
            [3] = 1,
            [4] = 1,
            [5] = 1,
            [6] = 1,
            [7] = 1,
            [8] = 0.5f,
            [9] = 0.5f,
			[10] = 1,
            [11] = 0.5f,
            [12] = 0.5f,
            [20] = 0.5f,
            [21] = 1,
            [22] = 0.5f,
            [23] = 0.5f,
            [24] = 1,
            [25] = 1,
            [26] = 1,
            [27] = 1,
            [28] = 1,
            [29] = 1,
            [100] = 1,
        };

        public Dictionary<int, int> typeToPointEditor = new Dictionary<int, int>()
        {
            [1] = 1,
            [2] = 1,
            [3] = 1,
            [7] = 1,
            [21] = 1,
            [100] = 1,
        };

        // 地图块交通
        GameObject mapChunckTrafficObj;
        TrafficPoint trafficDragObj;
        TrafficPoint trafficDragEndObj;
        bool DevelopmentToolsGFoldOut = false;
        bool bEditorTrafficData = false;
        #endregion

        [MenuItem("GTATools/GamePlay/SandBox/MapTools/Map/地图工具集合 %m")]
        static void AddWindow()
        {
            CreateMapEditorWindow window = (CreateMapEditorWindow)GetWindow(typeof(CreateMapEditorWindow), true, "MapTools"); // 不要固定大小 所有用GetWindow最好 设置一个最小大小就可以
            window.Show();
            window.minSize = new Vector2(600, 600);
        }

        public static void Init()
        {
            var window = EditorWindow.GetWindow<CreateMapEditorWindow>("GTA地圖生成工具", true);
        }

        protected void OnEnable()
        {
            //使用当前类初始化
            _serializedObject = new SerializedObject(this);
            //获取当前类中可序列话的属性
            _assetLstProperty = _serializedObject.FindProperty("mapChuncks");
            // 添加屏幕监听
            SceneView.duringSceneGui += OnSceneGUI;
        }

        private void OnDisable()
        {
            // 去除屏幕监听
            SceneView.duringSceneGui -= OnSceneGUI;
        }

        void OnSceneGUI(SceneView sceneView)
        {
            if (bSetPlaneType && Selection.gameObjects.Length > 0)
            {
                // 查找对应的选中目标
                GameObject selectObj = null;
                for (int i = 0; i < Selection.gameObjects.Length; i++)
                {
                    GameObject obj = Selection.gameObjects[i];
                    if (obj.GetComponent<MeshRenderer>() && obj.layer == LayerMask.NameToLayer("MapPoint"))
                    {
                        selectObj = obj;
                        break;
                    }
                }
                if (selectObj != null)
                {
                    Vector3 pos = selectObj.transform.position;
                    if (chunckCenter)
                    {
                        pos = pos - chunckCenter.transform.position;
                    }

                    //操作句柄
                    pointSpecialCfgMap.TryGetValue(selectObj, out string value);
                    string selectStr = "相对坐标 - " + selectObj.transform.name + " : " + pos;
                    if (!string.IsNullOrEmpty(value)) selectStr = selectStr + "\n点特殊配置:" + value;

                    Handles.Label(selectObj.transform.position, selectStr);
                }
            }

            if (bSetPointCfg && !bSetPlaneType)
            {
                foreach (var gameObject in pointSpecialCfgMap.Keys)
                {
                    Handles.Label(gameObject.transform.position, "点特殊配置:" + pointSpecialCfgMap[gameObject]);
                }
            }

            if (DevelopmentToolLineFoldOut)
            {
                Event guiEvent = Event.current;
                if (guiEvent != null)
                {
                    Ray mouseRay = HandleUtility.GUIPointToWorldRay(guiEvent.mousePosition);
                    float drawPlaneHeight = 0;
                    float dstToDrawPlane = (drawPlaneHeight - mouseRay.origin.y) / mouseRay.direction.y;
                    Vector3 mousePosition = mouseRay.GetPoint(dstToDrawPlane);

                    if (guiEvent.type == EventType.MouseDown && guiEvent.button == 0 && guiEvent.modifiers == EventModifiers.Shift)
                    {
                        if (_curLineObj)
                        {
                            int nodeNum = _curLineObj.transform.childCount;
                            if (nodeNum > 17)
                            {
                                EditorUtility.DisplayDialog("警告", "当前选中路线交货点已达到上限", "ok");
                                return;
                            }
                            // 路线根节点 - 路线curLineIdx - 交货点curNodeIdx - 路点
                            Transform nodeRooTf = _curLineObj.transform;
                            GameObject node = GameObject.CreatePrimitive(PrimitiveType.Sphere);
                            node.transform.parent = nodeRooTf;
                            node.name = "交货点_" + nodeNum.ToString();
                            node.transform.position = mousePosition;
                            _curNodeObj = node;
                            Selection.activeObject = node;
                        }
                        else
                        {
                            EditorUtility.DisplayDialog("警告", "请先 生成/选中 一条路线", "ok");
                        }
                    }

                    if (guiEvent.type == EventType.MouseDown && guiEvent.button == 1 && guiEvent.modifiers == EventModifiers.Shift)
                    {
                        if (_curNodeObj)
                        {
                            Transform nodeTf = _curNodeObj.transform;
                            GameObject roadNode = GameObject.CreatePrimitive(PrimitiveType.Sphere);
                            roadNode.transform.localScale = Vector3.one * 0.5f;
                            roadNode.transform.parent = nodeTf;
                            roadNode.transform.position = mousePosition;
                            roadNode.name = "路点";
                        }
                        else
                        {
                            EditorUtility.DisplayDialog("警告", "请先 生成/选中 一个交货点", "ok");
                        }
                   
                    }
                }

                // 更新路线显示
                if (_curLineObj)
                {
                    LineRenderer lineRender = _curLineObj.GetComponent<LineRenderer>();
                    List<Vector3> pos = new List<Vector3>();
                    for (int i = 0; i < _curLineObj.transform.childCount; i++)
                    {
                        Transform nodeTf = _curLineObj.transform.GetChild(i);
                        pos.Add(nodeTf.position);
                        for (int ii = 0; ii < nodeTf.childCount; ii++)
                        {
                            Transform roadNodeTf = nodeTf.transform.GetChild(ii);
                            pos.Add(roadNodeTf.position);
                        }
                    }
                    lineRender.positionCount = pos.Count;
                    lineRender.SetPositions(pos.ToArray());

                }
            }
        }

        private void OnGUI()
        {
            // 初始化调用
            if (GUIArr == null || GUIArr.Length <= 0)
            {
                InitIconTabs();
                InitEditorColor();
                m_tabBtnStyle = new GUIStyle("flow node 0");
                m_tabBtnStyle.alignment = TextAnchor.MiddleCenter;
                m_tabBtnStyle.fontSize = 18;
            }
            GUILayout.BeginHorizontal();
            for (int i = 0; i < GUIArr.Length; ++i)
            {
                GUILayout.Space(3);
                if (GUILayout.Toggle(m_Tab == (ETAB)i,GUIArr[i],"ButtonMid",GUILayout.Width(200)))m_Tab = (ETAB)i;
            }
            GUILayout.EndHorizontal();
            GUILayout.Space(5);
            switch (m_Tab)
            {
                case ETAB.ChunckEditor:
                    OnGUIChunck();
                    break;
                case ETAB.MapEditor:
                    OnGUIMap();
                    break;
                case ETAB.Other:
                    if (GUILayout.Button("打开预制体放置工具"))
                    {
                        PrefabPainter window = (PrefabPainter)EditorWindow.GetWindow(typeof(PrefabPainter));
                        window.ShowUtility();
                    }
                    break;
            }

        }

        private void Update()
        {
            if (m_Tab == ETAB.ChunckEditor && Selection.gameObjects.Length > 0 && bSetPlaneType)
            {
                for (int i = 0; i < Selection.gameObjects.Length; i++)
                {
                    SetPointType(Selection.gameObjects[i], (int)curType);
                }
            }
            if (m_Tab == ETAB.ChunckEditor && Selection.gameObjects.Length > 0 && bSetPointCfg)
            {
                string cfgStr = "";
                for (int i = 0; i < pointSpecialCfg.Count; i++)
                {
                    cfgStr += pointSpecialCfg[i].ToString() + "|";
                }
                for (int i = 0; i < Selection.gameObjects.Length; i++)
                {
                    GameObject obj = Selection.gameObjects[i];
                    if (pointSpecialCfg.Count == 0)
                    {
                        // 没有配置 删除
                        if (pointSpecialCfgMap.ContainsKey(obj)) pointSpecialCfgMap.Remove(obj);
                    }
                    else
                    {
                        pointSpecialCfgMap[obj] = cfgStr;
                    }
                }
            }
            if (bMapChunckDebug)
            {
                for (int i = 0; i < Selection.gameObjects.Length; i++)
                {
                    GameObject obj = Selection.gameObjects[i];
                    if (MapChunckLevelMap.ContainsKey(obj))
                    {
                        if (MapChunckLevelMap[obj] != MapChunckDebugLevel)
                        {
                            MapChunckLevelMap[obj] = MapChunckDebugLevel;
                            Color c = mapChunckLevelColor[MapChunckDebugLevel];
                            MeshRenderer r = obj.GetComponentInChildren<MeshRenderer>();
                            if (r) r.material.SetColor("_TintColor", c);
                            if (r) r.material.SetColor("_Tint", c);

                            r = obj.GetComponent<MeshRenderer>();
                            if (r) r.material.SetColor("_TintColor", c);
                            if (r) r.material.SetColor("_Tint", c);
                        }
                    }
                }
            }

      
        }

        private void Awake()
        {
            SceneView.duringSceneGui += SceneGUI;
            SceneView.beforeSceneGui += SceneGUIbefore;
            SetDraw(false);
        }

        private void OnDestroy()
        {
            SceneView.duringSceneGui -= SceneGUI;
            SceneView.beforeSceneGui -= SceneGUIbefore;
            EndMapAreaEditor();
            if (mapChunckRoot) DestroyImmediate(mapChunckRoot);
            if (mapPointRoot) DestroyImmediate(mapPointRoot);
            UnityEditor.Tools.lockedLayers = 0;
            SetDraw(true);
            DisposeChunckEditorRes();
            GeneralMap.OnDestroySelf();
            DisPoseFogEditor();
        }

        private void InitIconTabs()
        {
            string iconPath = "Assets/Arts/Tools/MapTools/";
            Texture tx_chunck = AssetDatabase.LoadAssetAtPath<Texture>(iconPath + "mapeditor_chuck.png");
            Texture tx_all = AssetDatabase.LoadAssetAtPath<Texture>(iconPath + "mapeditor_all.png"); 
            Texture tx_other = AssetDatabase.LoadAssetAtPath<Texture>(iconPath + "mapeditor_other.png"); 
            GUIArr = new GUIContent[]{  EditorGUIUtility.TrIconContent(tx_chunck,"地图块") ,
                                    EditorGUIUtility.TrIconContent(tx_all,"地图") ,
                                    EditorGUIUtility.TrIconContent(tx_other,"其他") };
        }

        enum E_EditorColorInitType  {
            E_AreaColor = 1,
            E_MapChunckColor = 2,
            E_MapChunckLevel = 3,
        }

        private void InitEditorColor()
        {
            // 读取
            TextAsset content = AssetDatabase.LoadAssetAtPath<TextAsset>("Assets/Editor/EditorCfg/MapEditorColor.txt");
            if (content != null && content.text != null && content.text.Length > 0)
            {
                var csvText = content.text.Trim();
                var lines = csvText.Split(new char[1] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
                //
                int initType = 0; // 颜色解析函数类型
                for (int i = 0; i < lines.Length; i++)
                {
                    var l = lines[i];// 2({182,255,172},...)
                    if (l.Contains("//"))
                    {
                        initType++;
                        continue;
                    }
                    switch (initType)
                    {
                        case (int)E_EditorColorInitType.E_AreaColor:
                            InitMapAreaColor(l); // 解析区域颜色
                            break;
                        case (int)E_EditorColorInitType.E_MapChunckColor:
                            InitMapChunckColor(l); // 解析地图块颜色
                            break;
                        case (int)E_EditorColorInitType.E_MapChunckLevel:
                            InitMapChunckLevelColor(l); // 解析地图块性能分级颜色
                            break;
                        default:
                            break;
                    }

                }
            }
        }

        private void InitMapAreaColor(string l)
        {
            int index1 = l.IndexOf('(');
            int index2 = l.LastIndexOf(')');
            string levelContent = l.Substring(index1 + 1, index2 - index1 - 1);//  {182,255,172},...
            var lstr = l.Split('(');

            if (lstr.Length == 2)
            {
                int.TryParse(lstr[0], out int type); // 1
                List<Color> colors = new List<Color>();

                var levelstr = levelContent.Split(';');
                for (int ii = 0; ii < levelstr.Length; ii++)
                {
                    var l2 = levelstr[ii];// {182,255,172}

                    index1 = l2.IndexOf('{');
                    index2 = l2.LastIndexOf('}');
                    string levelContent2 = l2.Substring(index1 + 1, index2 - index1 - 1);// 182,255,172
                    var colorstr = levelContent2.Split(',');
                    float.TryParse(colorstr[0], out float r); // r
                    float.TryParse(colorstr[1], out float g); // g
                    float.TryParse(colorstr[2], out float b); // b
                    colors.Add(new Color(r / 255.0f, g / 255.0f, b / 255.0f));
                }
                mapAreaInfoEditorColor[(mapAreaEditorType)type] = colors;
            }
        }

        private void InitMapChunckColor(string l)
        {
            var colors = l.Split('|');
            for (int i = 0; i < colors.Length; i++)
            {
                var l1 = colors[i];// 17-{255,0,0}
                var l2 = l1.Split('-');
                if (l2.Length != 2) continue;
                int.TryParse(l2[0], out int chunckResId); // 17

                int index1 = l2[1].IndexOf('{');
                int index2 = l2[1].LastIndexOf('}');
                var colorContent = l2[1].Substring(index1 + 1, index2 - index1 - 1);//  {255,0,0}
                var colorstr = colorContent.Split(',');//  255,0,0
                float.TryParse(colorstr[0], out float r); // r 255
                float.TryParse(colorstr[1], out float g); // g 0
                float.TryParse(colorstr[2], out float b); // b 0
                mapChunckEditorColor[chunckResId] = new Color(r, g, b);
            }
        }

        private void InitMapChunckLevelColor(string l)
        {
            var colors = l.Split('|');
            for (int i = 0; i < colors.Length; i++)
            {
                var l1 = colors[i];// 0-{255,0,0}
                var l2 = l1.Split('-');
                if (l2.Length != 2) continue;
                int.TryParse(l2[0], out int chunckLevel); // 0

                int index1 = l2[1].IndexOf('{');
                int index2 = l2[1].LastIndexOf('}');
                var colorContent = l2[1].Substring(index1 + 1, index2 - index1 - 1);//  {255,0,0}
                var colorstr = colorContent.Split(',');//  255,0,0
                float.TryParse(colorstr[0], out float r); // r 255
                float.TryParse(colorstr[1], out float g); // g 0
                float.TryParse(colorstr[2], out float b); // b 0
                mapChunckLevelColor[chunckLevel] = new Color(r / 255, g / 255, b / 255);
            }
        }
        private void OnGUIMap()
        {
            EditorGUILayout.BeginHorizontal();
            scrollPos = EditorGUILayout.BeginScrollView(scrollPos, false, false);
            
            if (_generalMap == null)
            {
                _generalMap = new GeneralMap();
            }
            _generalMap.mapName = EditorGUILayout.TextField("地图文件名", _generalMap.mapName);
            _generalMap.Lod = EditorGUILayout.IntField("地图Lod", _generalMap.Lod);
            _generalMap.Size = EditorGUILayout.IntField("地图tile尺寸", _generalMap.Size);
            _generalMap.tileWidth = EditorGUILayout.IntField("TILE_WIDTH", _generalMap.tileWidth);
            _generalMap.tileHeight = EditorGUILayout.IntField("TILE_HEIGHT", _generalMap.tileHeight);
            _generalMap.wSize = EditorGUILayout.IntField("Width", _generalMap.wSize);
            _generalMap.hSize = EditorGUILayout.IntField("Height", _generalMap.hSize);
            // EditorGUILayout.EndHorizontal();
            EditorGUILayout.Space();
            EditorGUILayout.BeginHorizontal();
            GUILayout.Label("地图存储路径:");
            GeneralMap.savePath = EditorGUILayout.TextField(GeneralMap.savePath);
            if (GUILayout.Button("浏览"))
            {
                EditorApplication.delayCall += SelectMapSaveFolder;
            }
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.Space();
            EditorGUILayout.BeginHorizontal();
            if (GUILayout.Button("生成地图节点"))
            {
                var result = _generalMap.generalMap();
                var msg = result ? "地图生成成功" : "地图生成失败";
                EditorUtility.DisplayDialog("通知", msg, "OK");

            }
            EditorGUILayout.BeginVertical();
            _serializedObject.Update();
            EditorGUI.BeginChangeCheck();
            EditorGUILayout.PropertyField(_assetLstProperty, true);
            if (EditorGUI.EndChangeCheck())
            {
                _serializedObject.ApplyModifiedProperties();
            }
            EditorGUILayout.EndVertical();
            if (GUILayout.Button("铺满地图"))
            {
                if (mapChuncks.Count > 0)
                {
                    System.Random random = new System.Random();
                    for (int y = 0; y < _generalMap.hSize; y++)
                    {
                        for (int x = 0; x < _generalMap.wSize; x++)
                        {
                            int idx = random.Next(0, mapChuncks.Count);
                            GameObject tile = PrefabUtility.InstantiatePrefab(mapChuncks[idx].gameObject) as GameObject;
                            tile.transform.position = new Vector3((x + 0.5f) * _generalMap.tileWidth, 0, (y + 0.5f) * _generalMap.tileHeight);
                            tile.gameObject.name = "TILE<" + AssetDatabase.GetAssetPath(mapChuncks[idx].gameObject) + ">";
                            if (GeneralMap.mapObj != null) tile.transform.SetParent(GeneralMap.mapObj.transform, false);
                        }
                    }
                }
                else
                {
                    ShowNotification(new GUIContent("请先添加铺设的地图块"));
                }
            }
            EditorGUILayout.EndHorizontal();
            EditorGUILayout.Space();
            EditorGUILayout.BeginHorizontal();
            GeneralMap.mapObj = (GameObject)EditorGUILayout.ObjectField("地图对象", GeneralMap.mapObj, typeof(GameObject), true);
            EditorGUILayout.EndHorizontal();
            GUI.enabled = GeneralMap.mapObj != null;
            if (GUILayout.Button("保存地图"))
            {
                if (GeneralMap.mapObj == null)
                {
                    EditorUtility.DisplayDialog("警告", "地图对象不能为空", "ok");
                }
                else if (_generalMap.mapName == String.Empty)
                {
                    EditorUtility.DisplayDialog("警告", "mapName为空", "ok");
                }
                else
                {
                    if (GeneralMap.SaveMap(GeneralMap.mapObj))
                    {
                        EditorUtility.DisplayDialog("通知", "保存成功", "ok");
                    }
                    else
                    {
                        EditorUtility.DisplayDialog("通知", "保存失败", "ok");
                    }
                }
            }
            GUI.enabled = true;
            _worldMap = (WorldMapData)EditorGUILayout.ObjectField("地图存储数据", _worldMap, typeof(WorldMapData), true);
            GUILayout.Label("是否显示海外区域(点数据导出必备):", GUILayout.Width(300));
            bShowOverSeaChunck = EditorGUILayout.Toggle(bShowOverSeaChunck, GUILayout.Width(150));
            GUI.enabled = _worldMap != null;
           
            if (GUILayout.Button("打开地图文件"))
            {
                if (GeneralMap._OpenWorldMapData(_worldMap,mapChunckEditorColor, bShowOverSeaChunck))
                {
                    EditorUtility.DisplayDialog("通知", "生成成功", "ok");
                }
                else
                {
                    EditorUtility.DisplayDialog("通知", "生成失败", "ok");
                }
            }
        

            //
            //GUILayout.Label("裁切左侧X:", GUILayout.Width(40));
            //cropVec4.x = EditorGUILayout.FloatField(cropVec4.x, GUILayout.Width(100));
            //GUILayout.Label("裁切右侧X:", GUILayout.Width(40));
            //cropVec4.y = EditorGUILayout.FloatField(cropVec4.y, GUILayout.Width(100));
            //GUILayout.Label("裁切下侧X:", GUILayout.Width(40));
            //cropVec4.z = EditorGUILayout.FloatField(cropVec4.z, GUILayout.Width(100));
            //GUILayout.Label("裁切上侧X:", GUILayout.Width(40));
            //cropVec4.w = EditorGUILayout.FloatField(cropVec4.w, GUILayout.Width(100));
            //if (GUILayout.Button("裁切地图数据"))
            //{
            //    if (cropVec4.x < 0 || cropVec4.y < 0 || cropVec4.z < 0 || cropVec4.w < 0)
            //    {
            //        EditorUtility.DisplayDialog("通知", "填入正确的裁切参数", "ok");
            //    }
            //    GeneralMap.CropWorldMapData(_worldMap, cropVec4);
            //}
            //if (GUILayout.Button("裁切区域数据"))
            //{
            //    if (cropVec4.x < 0 || cropVec4.y < 0 || cropVec4.z < 0 || cropVec4.w < 0)
            //    {
            //        EditorUtility.DisplayDialog("通知", "填入正确的裁切参数", "ok");
            //    }
            //    CropWorldMapAreaData();
            //}

            //if (GUILayout.Button("修改地图文件"))
            //{
            //    ResetWorldMapData(_worldMap);
            //}
            GUI.enabled = true;
            if (GUILayout.Button("检查地图预制体映射表"))
            {
                GeneralMap.CheckMapPrefabMap();
            }
            EditorGUILayout.BeginHorizontal();
            GUILayout.Label("是否显示打点数据:", GUILayout.Width(110));
            bShowMapPoint = EditorGUILayout.Toggle(bShowMapPoint, GUILayout.Width(150));
            EditorGUILayout.EndHorizontal();
            if (GUILayout.Button("导出地图打点数据 -服务器用"))
            {
                wirteMapPointJson();
            }

            EditorGUILayout.Space();

            OnGUIofToolLodData();

            OnGUIofToolMapArea();

            OnGUIofToolReplace();

            OnGUIofToolMapRoad();

            OnGUIofToolMapLine();

            EditorGUILayout.EndScrollView();
            EditorGUILayout.EndHorizontal();
        }

        private void OnGUIChunck()
        {
            // 地图预制体
            EditorGUILayout.BeginVertical();
            EditorGUILayout.BeginHorizontal(); 
            GUILayout.Label("地图块初始预制体:", GUILayout.Width(100));
            mapChunckRoot = EditorGUILayout.ObjectField("", mapChunckRoot, typeof(GameObject), true, GUILayout.Width(300)) as GameObject;
            if (mapChunckRoot) chuckDataName = mapChunckRoot.name + "_pointdata";
            if (GUILayout.Button("生成地图块")) CreateMapChunck();
            EditorGUILayout.EndHorizontal();
            EditorGUILayout.EndVertical();
            OnGUIofChunckElemnt();
            OnGUIofToolChunck();
            OnGUIofToolPointAdorn();
            //OnGUIofToolTraffic();

            //OnGUIofToolPerformance();

        }
        private void OnGUIofChunckElemnt()
        {
            DevelopmentToolsChunckElment = FoldoutReset(DevelopmentToolsChunckElment, "地图块出生点相关");
            if (DevelopmentToolsChunckElment)
            {
                // 打点预制体
                EditorGUILayout.BeginHorizontal();
                GUILayout.Label("元素尺寸:", GUILayout.Width(80));
                s_mapElementSize = EditorGUILayout.TextField(s_mapElementSize, GUILayout.Width(150));
                float.TryParse(s_mapElementSize, out mapElementSize);
                GUILayout.Space(20);
                mapElement = EditorGUILayout.ObjectField("地图元素预制体", mapElement, typeof(GameObject), true, GUILayout.Width(300)) as GameObject;
                EditorGUILayout.EndHorizontal();
                if (GUILayout.Button("生成地图元素")) CreateMapElement(Vector3.zero, 0);
                // 设置类型
                EditorGUILayout.BeginHorizontal();
                GUILayout.Label("是否开启类型设置:", GUILayout.Width(110));
                EditorGUI.BeginChangeCheck();
                bSetPlaneType = EditorGUILayout.Toggle(bSetPlaneType, GUILayout.Width(150));
                if (EditorGUI.EndChangeCheck())
                {
                    if (bSetPlaneType)
                    {
                        UnityEditor.Tools.lockedLayers |= ~(1 << LayerMask.NameToLayer("MapPoint"));
                    }
                    else
                    {
                        UnityEditor.Tools.lockedLayers = 0;
                    }
                }
                GUILayout.Space(20);
                curType = (ChunckElementType)EditorGUILayout.EnumPopup("当前类型", curType, GUILayout.Width(300));
                GUILayout.Space(20);
                chunckCenter = EditorGUILayout.ObjectField("地图块中心点", chunckCenter, typeof(GameObject), true, GUILayout.Width(300)) as GameObject;
                EditorGUILayout.EndHorizontal();
                // 设置特殊参数
                EditorGUILayout.BeginHorizontal();
                GUILayout.Label("是否开启参数设置:", GUILayout.Width(110));
                EditorGUI.BeginChangeCheck();
                bSetPointCfg = EditorGUILayout.Toggle(bSetPointCfg, GUILayout.Width(150));
                if (EditorGUI.EndChangeCheck())
                {
                    if (bSetPointCfg)
                    {
                        UnityEditor.Tools.lockedLayers |= ~(1 << LayerMask.NameToLayer("MapPoint"));
                    }
                    else
                    {
                        UnityEditor.Tools.lockedLayers = 0;
                    }
                }
                for (int i = 0; i < pointSpecialCfg.Count; i++)
                {
                    pointSpecialCfg[i] = EditorGUILayout.IntField(pointSpecialCfg[i]);
                }
                if (GUILayout.Button("+",GUILayout.Width(30))) {
                    pointSpecialCfg.Add(0);
                };
                if (GUILayout.Button("-", GUILayout.Width(30))) {
                    if (pointSpecialCfg.Count > 0)
                    pointSpecialCfg.RemoveAt(pointSpecialCfg.Count - 1);
                };
                EditorGUILayout.EndHorizontal();
                // 导出导入
                mapPlaneRoot = EditorGUILayout.ObjectField("导出根节点", mapPlaneRoot, typeof(GameObject), true, GUILayout.Width(300)) as GameObject;
                if (GUILayout.Button("导出地图出生点数据")) ExportChunckPointData();
                if (GUILayout.Button("加载地图出生点数据")) EditorCoroutines.StartCoroutine(LoadChunckPointData(), this);
                
                GUI.enabled = true;
            }
        }

        #region 大地图相关函数

        private void OnGUIofToolLodData()
        {
            DevelopmentToolsDFoldOut = FoldoutReset(DevelopmentToolsDFoldOut, "地图数据生成");
            if (DevelopmentToolsDFoldOut)
            {
                EditorGUI.BeginChangeCheck();
                EditorGUILayout.Space();

                // 组合地图数据
                _worldMap1 = (WorldMapData)EditorGUILayout.ObjectField("地图数据Lod1", _worldMap1, typeof(WorldMapData), true);
                if (GUILayout.Button("由Lod1地图数据生成整个地图数据"))
                {
                    if(_worldMap1 == null) EditorUtility.DisplayDialog("警告", "没有选中lod数据", "ok");
                    WorldMapData mapData = ScriptableObject.CreateInstance<WorldMapData>();
                    mapData.mapWidth = _generalMap.wSize * _generalMap.tileWidth;
                    mapData.mapHeight = _generalMap.hSize * _generalMap.tileHeight;
                    // 由lod1生成整个大地图的方法 -现在lod1~lod3使用的是地图块Lod1的数据 lod4使用的是地图块Lod2数据 lod5使用的单独的2D场景
                    // 注：现在整个大地图都是由lod1数据生成的 如果以后高层级Lod地图块的size和Lod1不一样 需要修改导出方法
                    // 1 设置各层级地图块id数据
                    mapData.mapLODDatas.Add(_worldMap1.mapLODDatas[0]);// 添加lod1地图块数据
                    MapLODData lod2Data = new MapLODData();// 添加lod2地图块数据 -因为没有lod2大地图 所以这里直接用lod1的数据创建
                    MapLODData lod3Data = new MapLODData();// 添加lod3地图块数据
                    MapLODData lod4Data = new MapLODData();// 添加lod4地图块数据
                    lod2Data.lodDistance = 2;
                    lod2Data.tileSize = 30;
                    lod3Data.lodDistance = 3;
                    lod3Data.tileSize = 30;
                    lod4Data.lodDistance = 4;
                    lod4Data.tileSize = 30;
                    List<int> mapLod1ChunckIds = _worldMap1.mapLODDatas[0].mapChunckIds;
                    List<int> mapLod2ChunckIds = new List<int>();
                    List<int> mapLod3ChunckIds = new List<int>();
                    List<int> mapLod4ChunckIds = new List<int>();

                    List<OverSeaChunck> mapLod1EdgeChuncks = _worldMap1.mapLODDatas[0].mapOverSeaChuncks;
                    List<OverSeaChunck> mapLod2EdgeChuncks = new List<OverSeaChunck>();
                    List<OverSeaChunck> mapLod3EdgeChuncks = new List<OverSeaChunck>();
                    List<OverSeaChunck> mapLod4EdgeChuncks = new List<OverSeaChunck>();

                    for (int i = 0; i < mapLod1ChunckIds.Count; i++)
                    {
                        int lod1ChunckId = mapLod1ChunckIds[i];
                        chunckInfoDta data = GeneralMap.GetChunckInfoById(lod1ChunckId);
                        data.lod = 3;
                        int lod1ChunckId_3 = GeneralMap.GetChunckIdByInfo(data);
                        if (lod1ChunckId_3 > 0)
                        {
                            mapLod4ChunckIds.Add(lod1ChunckId_3);
                        }
                        mapLod3ChunckIds.Add(lod1ChunckId); // lod3也用模型
                        mapLod2ChunckIds.Add(lod1ChunckId);
                    }
                    lod2Data.mapChunckIds = mapLod2ChunckIds;
                    lod3Data.mapChunckIds = mapLod3ChunckIds;
                    lod4Data.mapChunckIds = mapLod4ChunckIds;

                    for (int i = 0; i < mapLod1EdgeChuncks.Count; i++)
                    {
                        OverSeaChunck lod1EdgeChunck = mapLod1EdgeChuncks[i];
                        chunckInfoDta data = GeneralMap.GetChunckInfoById(lod1EdgeChunck.chunckId);
                        data.lod = 3;
                        int lod1ChunckId_3 = GeneralMap.GetChunckIdByInfo(data);
                        if (lod1ChunckId_3 > 0)
                        {
                            OverSeaChunck edge = new OverSeaChunck(lod1EdgeChunck);
                            edge.chunckId = lod1ChunckId_3;
                            mapLod4EdgeChuncks.Add(edge);
                        }
                        mapLod2EdgeChuncks.Add(lod1EdgeChunck);
                        mapLod3EdgeChuncks.Add(lod1EdgeChunck);
                    }
                    lod2Data.mapOverSeaChuncks = mapLod2EdgeChuncks;
                    lod3Data.mapOverSeaChuncks = mapLod3EdgeChuncks;
                    lod4Data.mapOverSeaChuncks = mapLod4EdgeChuncks;
                    mapData.mapLODDatas.Add(lod2Data);// 添加lod2地图块数据
                    mapData.mapLODDatas.Add(lod3Data);// 添加lod3地图块数据
                    mapData.mapLODDatas.Add(lod4Data);// 添加lod4地图块数据
                    // 2 设置各层级策略数据
                    // 添加地表层级
                    MapLayerRunDta planeRunData = new MapLayerRunDta();
                    planeRunData.layerID = WorldEntry.PLANE_LAYER_ID;
                    planeRunData.name = WorldEntry.PLANE_LAYER_NAME;
                    planeRunData.displayLods = new List<int2>();
                    planeRunData.displayLods.Add(new int2(1, 30));
                    planeRunData.displayLods.Add(new int2(2, 30));
                    planeRunData.displayLods.Add(new int2(3, 30));
                    planeRunData.displayLods.Add(new int2(4, 30));
                    mapData.mapLayerRunDtas.Add(planeRunData);
                    // 添加树(装饰物)层级
                    MapLayerRunDta treeRunData = new MapLayerRunDta();
                    treeRunData.layerID = WorldEntry.TREE_LAYER_ID;
                    treeRunData.name = WorldEntry.TREE_LAYER_NAME;
                    treeRunData.displayLods = new List<int2>();
                    treeRunData.displayLods.Add(new int2(1, 30));// 树只开放lod1层级
                    mapData.mapLayerRunDtas.Add(treeRunData);
                    // 添加阻挡层级
                    //MapLayerRunDta mountainrangeRunData = new MapLayerRunDta();
                    //mountainrangeRunData.layerID = WorldEntry.MOUNTAINRANGE_LAYER_ID;
                    //mountainrangeRunData.name = WorldEntry.MOUNTAINRANGE_LAYER_NAME;
                    //mountainrangeRunData.displayLods = new List<int2>();
                    //mountainrangeRunData.displayLods.Add(new int2(1, 30));
                    //mountainrangeRunData.displayLods.Add(new int2(2, 30));
                    //mountainrangeRunData.displayLods.Add(new int2(3, 30));
                    //mountainrangeRunData.displayLods.Add(new int2(4, 30));
                    //mapData.mapLayerRunDtas.Add(mountainrangeRunData);
                    // 添加出生点层级
                    MapLayerRunDta mapPointRunData = new MapLayerRunDta();
                    mapPointRunData.layerID = WorldEntry.MAP_POINT_ID;
                    mapPointRunData.name = WorldEntry.MAP_POINT_NAME;
                    mapPointRunData.displayLods = new List<int2>();
                    mapPointRunData.displayLods.Add(new int2(1, 30));// 出生点只开放lod1层级
                    mapData.mapLayerRunDtas.Add(mapPointRunData);
                    // 将所有地图块id填充到大地图数据中
                    Dictionary<int, bool> mapChunckResIdMap = new Dictionary<int, bool>();
                    for (int i = 0;i < mapData.mapLODDatas.Count;i++)
                    {
                        var lodData = mapData.mapLODDatas[i];
                        for (int ii = 0; ii < lodData.mapChunckIds.Count; ii++)
                        {
                            int id = lodData.mapChunckIds[ii];
                            // 只填充不旋转的
                            chunckInfoDta chunckInfoDta = GeneralMap.GetChunckInfoById(id);
                            chunckInfoDta.radio = 0;
                            int id_0 = GeneralMap.GetChunckIdByInfo(chunckInfoDta);
                            if (!mapChunckResIdMap.ContainsKey(id_0))
                            {
                                mapChunckResIdMap[id_0] = true;
                                mapData.AddMapChunckResId(id_0);
                            }
                          
                        }
                        // 边界也填充一下
                        for (int ii = 0; ii < lodData.mapOverSeaChuncks.Count; ii++)
                        {
                            OverSeaChunck edge = lodData.mapOverSeaChuncks[ii];
                            int id = edge.chunckId;
                            // 只填充不旋转的
                            chunckInfoDta chunckInfoDta = GeneralMap.GetChunckInfoById(id);
                            chunckInfoDta.radio = 0;
                            int id_0 = GeneralMap.GetChunckIdByInfo(chunckInfoDta);
                            if (!mapChunckResIdMap.ContainsKey(id_0))
                            {
                                mapChunckResIdMap[id_0] = true;
                                mapData.AddMapChunckResId(id_0);
                            }
                        }
                    }
                    //
                    AssetDatabase.CreateAsset(mapData, GeneralMap.savePath + "/" + _generalMap.mapName + "_mapdata.asset");
                    //GeneralMap.ExportMapPrefabMap();
                }

                // 
                if (GUILayout.Button("导出删除街区点"))
                {
                    WorldMapData mapData = ScriptableObject.CreateInstance<WorldMapData>();
                    mapData.InitData(_worldMap1);
                    List<int> mapLod1ChunckIds = _worldMap1.mapLODDatas[0].mapChunckIds;
                    Dictionary<int, MapChunckData> dataDic = new Dictionary<int, MapChunckData>();

                    for (int i = 0; i < mapLod1ChunckIds.Count; i++)
                    {
                        int lod1ChunckId = mapLod1ChunckIds[i];
                        chunckInfoDta data = GeneralMap.GetChunckInfoById(lod1ChunckId);
                        MapChunckData mapChunckData = null;
                        if (dataDic.ContainsKey(lod1ChunckId))
                        {
                            mapChunckData = dataDic[lod1ChunckId];
                        }
                        else
                        {
                            string path = string.Format("Assets/ResourcesAssets/World/mapdata/sandtable_{0}_{1}_{2}_lod{3}_chuckData.asset",
                                        data.roadType, data.chunckType, 0, data.lod);
                            mapChunckData = AssetDatabase.LoadAssetAtPath<MapChunckData>(path);
                            dataDic[lod1ChunckId] = mapChunckData;
                        }
                        // 
                        int tileIdx = i;
                        Vector3 tileOffset = WorldMapConfigData.GetTileOffset(i);
                        for (int ii = 0; ii < mapChunckData.alliancePointRoads.Count; ii++)
                        {
                            TileAlliancePointRoad road = mapChunckData.alliancePointRoads[ii];
                            if (road.resID == 100)
                            { 
                                Vector3 localOffset = WorldMapConfigData.GetPosByAngle(road.position.x, 0, road.position.z, data.radio);
                                GameObject obj = GameObject.CreatePrimitive(PrimitiveType.Cube);
                                obj.transform.position = localOffset + tileOffset;

                                int _alliancePointSize = 10;
                                int _alliancePointLineNum = WorldEntry.m_mapSize / _alliancePointSize;
                                int idx_x = (int)(obj.transform.position.x / _alliancePointSize);
                                int idx_y = (int)(obj.transform.position.z / _alliancePointSize);
                                int idx = idx_x + idx_y * _alliancePointLineNum;
                                mapData.AddDeleateAllinacePointIdx(idx);
                            }
                        }

                    }
                    AssetDatabase.CreateAsset(mapData, GeneralMap.savePath + "/" + _generalMap.mapName + "_mapdata.asset");
                }
                GUI.enabled = true;
            }

        }    

        GameObject replaceChunck;
        float replaceX = 0;
        float replaceZ = 0;

        Vector4 cropVec4 = new Vector4();
   
        private void OnGUIofToolReplace()
        {
            DevelopmentToolReplaceFoldOut = FoldoutReset(DevelopmentToolReplaceFoldOut, "地图绘制相关");
            if (DevelopmentToolReplaceFoldOut)
            {
                GUILayout.BeginHorizontal();
                GUILayout.Label("替换用地图块:", GUILayout.Width(80));
                replaceChunck = (GameObject)EditorGUILayout.ObjectField("", replaceChunck, typeof(GameObject), true,GUILayout.Width(100));
                GUILayout.Space(10);
                GUILayout.Label("X坐标:", GUILayout.Width(40));
                replaceX = EditorGUILayout.FloatField(replaceX, GUILayout.Width(100));
                GUILayout.Space(10);
                GUILayout.Label("Y坐标:", GUILayout.Width(40));
                replaceZ = EditorGUILayout.FloatField(replaceZ, GUILayout.Width(100));
                if (GUILayout.Button("替换"))
                {
                    if (GeneralMap.mapObj == null)
                    {
                        EditorUtility.DisplayDialog("警告", "地图对象不能为空", "ok");
                        return;
                    }
                    if (replaceChunck == null)
                    {
                        EditorUtility.DisplayDialog("警告", "没有替换的预制体", "ok");
                        return;
                    }
                    Vector3 newPos = new Vector3(replaceX, 0, replaceZ);
                    // 先删除原有的地块
                    for (int i = 0; i < GeneralMap.mapObj.transform.childCount; i++)
                    {
                        Transform tf = GeneralMap.mapObj.transform.GetChild(i);
                        if (tf.position == newPos)
                        {
                            GameObject.DestroyImmediate(tf.gameObject);
                            break;
                        }
                    }
                    GameObject tile = PrefabUtility.InstantiatePrefab(replaceChunck) as GameObject;
                    tile.transform.position = newPos;
                    tile.gameObject.name = string.Format("TILE<Assets/ResourcesAssets/World/prefabs/sandtable/tiles/{0}.prefab>",replaceChunck.name);
                    if (GeneralMap.mapObj != null)
                    {
                        tile.transform.SetParent(GeneralMap.mapObj.transform, false);
                        Selection.activeGameObject = tile.gameObject;
                    }
                }

                // 绘制当前地图所有阻挡
                _worldMapObstruct = (WorldMapData)EditorGUILayout.ObjectField("地图阻挡数据", _worldMapObstruct, typeof(WorldMapData), true);
                if (GUILayout.Button("生成地图阻挡"))
                {
                    // 读取地图数据
                    if (_worldMapObstruct)
                    {
                        if (mapObstructRoot) GameObject.DestroyImmediate(mapObstructRoot);
                        mapObstructRoot = new GameObject();
                        mapObstructRoot.transform.position = Vector3.zero;
                        mapObstructRoot.name = "mapObstructRoot";
                        // 查找默认阻挡节点
                        _editorMapObstructRoot = GameObject.Find("地图阻挡根节点-保存各地图的阻挡");
                        for (int i = 0;i < _worldMapObstruct.mapLODDatas.Count;i++)
                        {
                            var lodData = _worldMapObstruct.mapLODDatas[i];
                            if (lodData.lodDistance == 1)
                            {
                                for (int ii = 0; ii < lodData.mapChunckIds.Count; ii++)
                                {
                                    int chunckId = lodData.mapChunckIds[ii];
                                    GeneralMap.CreateChunckObstruct(chunckId, ii, mapObstructRoot.transform, _editorMapObstructRoot.transform,null);
                                }
                                for (int ii = 0; ii < lodData.mapOverSeaChuncks.Count; ii++)
                                {
                                    int chunckId = lodData.mapOverSeaChuncks[ii].chunckId;
                                    GeneralMap.CreateChunckObstruct(chunckId, ii, mapObstructRoot.transform, _editorMapObstructRoot.transform, lodData.mapOverSeaChuncks[ii]);
                                }
                            }
                        }
                    }
                }
                GUILayout.EndHorizontal();
              
                GUI.enabled = true;
            }
        }

        private void OnGUIofToolMapLine()
        {
            DevelopmentToolLineFoldOut = FoldoutReset(DevelopmentToolLineFoldOut, "沙盘6车道路线相关");
            if (DevelopmentToolLineFoldOut)
            {
                if (_mapLineRoot == null)
                {
                    curLineIdx = 0;
                    curNodeIdx = -1;
                    _mapLineRoot = GameObject.Find("路线根节点");
                    if (_mapLineRoot == null)
                    {
                        _mapLineRoot = new GameObject("路线根节点");
                    }
                    else
                    { 
                        // 重新绑定所有数据
                    }
                }
                if (_mapTrainLineRoot == null)
                {
                    _mapTrainLineRoot = GameObject.Find("奇观路线根节点");
                    if (_mapTrainLineRoot == null)
                    {
                        _mapTrainLineRoot = new GameObject("奇观路线根节点");
                    }
                    else
                    { 
                        // 重新绑定所有数据
                    }
                }
                GUILayout.Label("=========================================走私车队路线=========================================");

                if (GUILayout.Button("加载当前地图和路线"))
                {
                    WorldMapData worldMap = AssetDatabase.LoadAssetAtPath<WorldMapData>("Assets/ResourcesAssets/World/mapdata/sandbox_lod1_mapdata_new.asset"); //(WorldMapData)EditorGUILayout.ObjectField("地图存储数据", _worldMap, typeof(WorldMapData), true);
                    GeneralMap._OpenWorldMapData(worldMap, mapChunckEditorColor);
                    GameObject road = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/ResourcesAssets/World/prefabs/sandtable/road/LineRenderRoad/sandbox_lod4_line_highway.prefab");
                    road = GameObject.Instantiate(road);
                    float halfSize = WorldEntry.m_mapSize * 0.5f;
                    road.transform.position = new Vector3(halfSize, 0, halfSize);
                }

                if (GUILayout.Button("新增走私车队路线"))
                {
                    // 新增路线
                    GameObject model = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/Arts/World/sandtable/prefabs/editor/editorLine.prefab");
                    GameObject lineRoot = GameObject.Instantiate(model);
                    lineRoot.name = "路线_" + _mapLineRoot.transform.childCount.ToString();
                    lineRoot.transform.parent = _mapLineRoot.transform;
                    _curLineObj = lineRoot;
                }

                GUILayout.Label("当前选中走私车队路线:", GUILayout.Width(80));
                _curLineObj = (GameObject)EditorGUILayout.ObjectField("", _curLineObj, typeof(GameObject), true, GUILayout.Width(100));


                GUILayout.Label("当前选中走私车队交货点:", GUILayout.Width(80));
                _curNodeObj = (GameObject)EditorGUILayout.ObjectField("", _curNodeObj, typeof(GameObject), true, GUILayout.Width(100));

                if (GUILayout.Button("打印选中走私车队路线的各段长度"))
                {
                    if (_curLineObj)
                    {
                        Debug.LogFormat("===================================== {0} =====================================", _curLineObj.name);
                        for (int i = 0; i < _curLineObj.transform.childCount - 1; i++)
                        {
                            float dis = 0;
                            Transform node = _curLineObj.transform.GetChild(i);
                            Transform nodeNext = _curLineObj.transform.GetChild(i + 1);
                            if (node.childCount > 0)
                            {
                                for (int ii = 0; ii < node.transform.childCount - 1; ii++)
                                {
                                    Transform roadNode = node.transform.GetChild(ii);
                                    Transform roadNodeNext = node.transform.GetChild(ii + 1);
                                    if (ii == 0)
                                    {
                                        dis += Vector3.Distance(node.position, roadNode.position);
                                    }
                                    else
                                    {
                                        dis += Vector3.Distance(roadNodeNext.position, roadNode.position);
                                    }
                                }
                                dis += Vector3.Distance(nodeNext.position, node.transform.GetChild(node.transform.childCount - 1).position);
                            }
                            else
                            {
                                dis = Vector3.Distance(node.position, nodeNext.position);
                            }
                           
                            Debug.LogFormat("{0} => {1} 的路线距离： {2}", node.gameObject.name, nodeNext.gameObject.name, dis);
                        }
                        Debug.Log("===================================== 打印结束 =====================================");
                    }
                  
                }

                if (GUILayout.Button("导出所有走私车队路线"))
                {
                    if (_mapLineRoot == null) return;
                    MapLineDatas data = new MapLineDatas();
                    data.lines = new List<MapLineData>();
                    for (int i = 0; i < _mapLineRoot.transform.childCount; i++)
                    {
                        Transform lineRoot = _mapLineRoot.transform.GetChild(i);
                        MapLineData lineData = new MapLineData();
                        lineData.nodes = new List<MapNodeData>();
                        for (int ii = 0; ii < lineRoot.transform.childCount; ii++)
                        {
                            Transform nodeRoot = lineRoot.transform.GetChild(ii);
                            MapNodeData nodeData = new MapNodeData();
                            nodeData.node = nodeRoot.position;
                            nodeData.point = new List<Vector3>();
                            for (int iii = 0; iii < nodeRoot.transform.childCount; iii++)
                            {
                                Transform roadNodeRoot = nodeRoot.transform.GetChild(iii);
                                nodeData.point.Add(roadNodeRoot.position);
                            }
                            lineData.nodes.Add(nodeData);
                        }
                        data.lines.Add(lineData);
                    }

                    var ms = new MemoryStream();
                    new DataContractJsonSerializer(data.GetType()).WriteObject(ms, data);
                    var json = Encoding.UTF8.GetString(ms.ToArray());

                    string path = Application.dataPath + "/ResourcesAssets/Config/Data/";
                    string filePath = path + "mapRoadPointData.json";
                    if (!Directory.Exists(path))
                    {
                        Directory.CreateDirectory(path);
                    }

                    StreamWriter streamWriter = new StreamWriter(filePath);

                    streamWriter.Write(json.ToString());
                    streamWriter.Flush();
                    streamWriter.Close();

                    AssetDatabase.Refresh();

                    EditorUtility.DisplayDialog("提示", "导出路线成功 请将ResourcesAssets/Config/Data/下mapRoadPointData.json 文件给到后端", "ok");
                }

                GUILayout.Label("=========================================奇观路线=========================================");
                GUILayout.Label("路线根节点:", GUILayout.Width(300));
                _mapLineRoot = (GameObject)EditorGUILayout.ObjectField("", _mapLineRoot, typeof(GameObject), true, GUILayout.Width(100));


                GUILayout.Label("衔接点根节点:", GUILayout.Width(300));
                _wonderCrossRoot = (GameObject)EditorGUILayout.ObjectField("", _wonderCrossRoot, typeof(GameObject), true, GUILayout.Width(100));

                if (GUILayout.Button("加载当前地图和道路"))
                {
                    WorldMapData worldMap = AssetDatabase.LoadAssetAtPath<WorldMapData>("Assets/ResourcesAssets/World/mapdata/sandbox_lod1_mapdata_new.asset"); //(WorldMapData)EditorGUILayout.ObjectField("地图存储数据", _worldMap, typeof(WorldMapData), true);
                    GeneralMap._OpenWorldMapData(worldMap, mapChunckEditorColor);
                    GameObject roadRoot = new GameObject("6车道根节点");
                    int mapSize = WorldEntry.m_mapLandSize;
                    int tileSize = mapSize / 5;
                    for (int x = 0; x < 5; x++)
                    {
                        for (int y = 0; y < 5; y++)
                        {
                            int roadIdx = x + y * 5;
                            string roadPath = string.Format("Assets/ResourcesAssets/World/prefabs/sandtable/road/LOD1/RoadNet_{0}.prefab", roadIdx);
                            GameObject road = AssetDatabase.LoadAssetAtPath<GameObject>(roadPath);
                            road = GameObject.Instantiate(road, roadRoot.transform);
                            float posX = (x + 0.5f) * tileSize;
                            float posY = (y + 0.5f) * tileSize;
                            road.transform.position = new Vector3(posX, 0, posY);
                            // 顺便添加阻挡
                            MeshRenderer[] renders = road.gameObject.GetComponentsInChildren<MeshRenderer>();
                            for (int i = 0; i < renders.Length; i++)
                            {
                                MeshRenderer render = renders[i];
                                render.gameObject.name = "road";
                                render.gameObject.AddComponent<MeshCollider>();
                            }
                        }
                    }
                }

                if (GUILayout.Button("导入所有奇观衔接点"))
                {
                    WorldMapData worldMap = AssetDatabase.LoadAssetAtPath<WorldMapData>("Assets/ResourcesAssets/World/mapdata/sandbox_lod1_mapdata_new.asset"); //(WorldMapData)EditorGUILayout.ObjectField("地图存储数据", _worldMap, typeof(WorldMapData), true);
                    _wonderCrossRoot = _CreateWonderEditorCross(worldMap);
                }

                GUILayout.Label("起始奇观衔接点:", GUILayout.Width(300));
                _startWonderCross = (GameObject)EditorGUILayout.ObjectField("", _startWonderCross, typeof(GameObject), true, GUILayout.Width(100));


                GUILayout.Label("结束奇观衔接点:", GUILayout.Width(300));
                _endWonderCross = (GameObject)EditorGUILayout.ObjectField("", _endWonderCross, typeof(GameObject), true, GUILayout.Width(100));

                if (GUILayout.Button("新增奇观路线"))
                {
                    GameObject model = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/Arts/World/sandtable/prefabs/editor/editorLine.prefab");
                    GameObject lineRoot = GameObject.Instantiate(model);
                    GameObject startWonderCross = GameObject.CreatePrimitive(PrimitiveType.Sphere);
                    startWonderCross.transform.position = _startWonderCross.transform.position;
                    startWonderCross.name = _startWonderCross.name;
                    startWonderCross.transform.parent = lineRoot.transform;
                    string startWonderId = _startWonderCross.transform.parent.name;

                    GameObject endWonderCross = GameObject.CreatePrimitive(PrimitiveType.Sphere);
                    endWonderCross.transform.position = _endWonderCross.transform.position;
                    endWonderCross.name = _endWonderCross.name;
                    endWonderCross.transform.parent = lineRoot.transform;
                    string endWonderId = _endWonderCross.transform.parent.name;

                    lineRoot.name = startWonderId + "_" + endWonderId + "_0"; // 起始奇观id_结束奇观id_时间
                    lineRoot.transform.parent = _mapLineRoot.transform;
                    lineRoot.gameObject.AddComponent<WonderLineTool>();
                }

                GUILayout.Label("当前选中的奇观路线:", GUILayout.Width(300));
                GameObject editorWonderLine = (GameObject)EditorGUILayout.ObjectField("", _editorWonderLine, typeof(GameObject), true, GUILayout.Width(100));
                if (editorWonderLine && editorWonderLine != _editorWonderLine)
                {
                    // 选中路线改变
                    Selection.activeGameObject = editorWonderLine;
                    _editorWonderLine = editorWonderLine;
                    string[] nameStrs = _editorWonderLine.name.Split("_");
                    if (nameStrs.Length == 3)
                    {
                        float.TryParse(nameStrs[2], out _editorWonderLineTime);
                    }
                    else
                    {
                        _editorWonderLineTime = 0;
                    }
                }

                GUILayout.Label("当前选中的奇观路线时间(秒):", GUILayout.Width(300));
                float editorWonderLineTime = EditorGUILayout.FloatField( _editorWonderLineTime,  GUILayout.Width(100));
                if (editorWonderLineTime != _editorWonderLineTime && _editorWonderLine)
                {
                    _editorWonderLineTime = editorWonderLineTime;
                    string[] nameStrs = _editorWonderLine.name.Split("_");
                    if (nameStrs.Length == 3)
                    {
                        _editorWonderLine.name = nameStrs[0] + "_" + nameStrs[1] + "_" + _editorWonderLineTime.ToString();
                    }
                    else
                    {
                        _editorWonderLine.name = _editorWonderLine.name + "_" + _editorWonderLineTime.ToString();
                    }
                }

                //if (GUILayout.Button("随机选中一条未编辑时间的奇观路线(方便编辑时间)"))
                //{ 
                
                //}

                if (GUILayout.Button("导出所有奇观路线"))
                {
                    if (_mapLineRoot == null) return;
                    WonderLineDatas data = new WonderLineDatas();
                    data.lines = new List<WonderLineData>();
                    Vector3 tempV3 = new Vector3(0,0,0);
                    for (int i = 0; i < _mapLineRoot.transform.childCount; i++)
                    {
                        Transform line = _mapLineRoot.transform.GetChild(i);
                        WonderLineData lineData = new WonderLineData();
                        lineData.points = new List<Vector3>();
                        string[] wonderNames = line.name.Split("_");
                        int.TryParse(wonderNames[0], out lineData.startWonderId);
                        int.TryParse(wonderNames[1], out lineData.endWonderId);
                        int wonderLineTime = 0;
                        if (wonderNames.Length == 3)
                        {
                            int.TryParse(wonderNames[2], out wonderLineTime);
                        }
                        if(wonderLineTime == 0)
                        {
                            // 存在路线没有编辑时间
                            EditorUtility.DisplayDialog("提示", string.Format("导出路线错误 请设置路线{0}的时间", line.name), "ok");
                            return;
                        }
                        lineData.wonderLineTime = wonderLineTime;
                        for (int ii = 0; ii < line.transform.childCount; ii++)
                        {
                            Transform point = line.transform.GetChild(ii);
                            if (ii == 0)
                            {
                                int.TryParse(point.name, out lineData.startCrossIdx);
                                continue;
                            }
                            if (ii == line.transform.childCount - 1)
                            {
                                int.TryParse(point.name, out lineData.endCrossIdx);
                                continue;
                            }
                            tempV3.x = point.transform.position.x;
                            tempV3.z = point.transform.position.z;
                            lineData.points.Add(tempV3);
                        }

                        data.lines.Add(lineData);
                    }
                    data.points = new List<WonderPointData>();
                    for (int i = 0; i < _wonderCrossRoot.transform.childCount; i++)
                    {
                        Transform cross = _wonderCrossRoot.transform.GetChild(i);
                        WonderPointData crossData = new WonderPointData();
                        int.TryParse(cross.name, out crossData.id);
                        crossData.points = new List<Vector3>();
                        for (int ii = 0; ii < cross.transform.childCount; ii++)
                        {
                            Transform point = cross.transform.GetChild(ii);
                            tempV3.x = point.transform.position.x;
                            tempV3.z = point.transform.position.z;
                            crossData.points.Add(tempV3);
                        }
                        data.points.Add(crossData);
                    }

                    var ms = new MemoryStream();
                    new DataContractJsonSerializer(data.GetType()).WriteObject(ms, data);
                    var json = Encoding.UTF8.GetString(ms.ToArray());

                    string path = Application.dataPath + "/ResourcesAssets/Config/Data/";
                    string filePath = path + "mapWonderLineData.json";
                    if (!Directory.Exists(path))
                    {
                        Directory.CreateDirectory(path);
                    }

                    StreamWriter streamWriter = new StreamWriter(filePath);

                    streamWriter.Write(json.ToString());
                    streamWriter.Flush();
                    streamWriter.Close();

                    AssetDatabase.Refresh();

                    EditorUtility.DisplayDialog("提示", "导出路线成功 请将ResourcesAssets/Config/Data/mapWonderLineData.json 文件给到后端", "ok");
                }
                
                GUILayout.Label("=========================================列车路线=========================================");
                GUILayout.Label("列车路线根节点:", GUILayout.Width(300));
                _mapTrainLineRoot = (GameObject)EditorGUILayout.ObjectField("", _mapTrainLineRoot, typeof(GameObject), true, GUILayout.Width(100));
                
                GUILayout.Label("奇观中心根节点:", GUILayout.Width(300));
                _wonderCenterRoot = (GameObject)EditorGUILayout.ObjectField("", _wonderCenterRoot, typeof(GameObject), true, GUILayout.Width(100));

                if (GUILayout.Button("1、加载当前地图"))
                {
                    WorldMapData worldMap = AssetDatabase.LoadAssetAtPath<WorldMapData>("Assets/ResourcesAssets/World/mapdata/sandbox_lod1_mapdata_new.asset"); //(WorldMapData)EditorGUILayout.ObjectField("地图存储数据", _worldMap, typeof(WorldMapData), true);
                    GeneralMap._OpenWorldMapData(worldMap, mapChunckEditorColor);
                }

                if (GUILayout.Button("2、导入所有奇观中心点"))
                {
                    WorldMapData worldMap = AssetDatabase.LoadAssetAtPath<WorldMapData>("Assets/ResourcesAssets/World/mapdata/sandbox_lod1_mapdata_new.asset"); //(WorldMapData)EditorGUILayout.ObjectField("地图存储数据", _worldMap, typeof(WorldMapData), true);
                    _wonderCenterRoot = _CreateWonderEditorCenter(worldMap);
                }
                GUILayout.Label("3.1、起始奇观中心点:", GUILayout.Width(300));
                _startWonderCenter = (GameObject)EditorGUILayout.ObjectField("", _startWonderCenter, typeof(GameObject), true, GUILayout.Width(100));


                GUILayout.Label("3.2、结束奇观中心点:", GUILayout.Width(300));
                _endWonderCenter = (GameObject)EditorGUILayout.ObjectField("", _endWonderCenter, typeof(GameObject), true, GUILayout.Width(100));

                if (GUILayout.Button("3.3、新增奇观路线"))
                {
                    GameObject model = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/Arts/World/sandtable/prefabs/editor/editorLine.prefab");
                    GameObject lineRoot = GameObject.Instantiate(model);
                    GameObject startWonderCross = GameObject.CreatePrimitive(PrimitiveType.Sphere);
                    startWonderCross.transform.position = _startWonderCenter.transform.position;
                    startWonderCross.name = _startWonderCenter.name;
                    startWonderCross.transform.parent = lineRoot.transform;
                    string startWonderId = _startWonderCenter.transform.parent.name;

                    GameObject endWonderCross = GameObject.CreatePrimitive(PrimitiveType.Sphere);
                    endWonderCross.transform.position = _endWonderCenter.transform.position;
                    endWonderCross.name = _endWonderCenter.name;
                    endWonderCross.transform.parent = lineRoot.transform;
                    string endWonderId = _endWonderCenter.transform.parent.name;

                    lineRoot.name = startWonderId + "_" + endWonderId + "_0"; // 起始奇观id_结束奇观id_时间
                    lineRoot.transform.parent = _mapTrainLineRoot.transform;
                    lineRoot.gameObject.AddComponent<WonderLineTool>();
                }
                GUILayout.Label("4.1、当前选中的列车路线:", GUILayout.Width(300));
                GameObject editorTrainLine = (GameObject)EditorGUILayout.ObjectField("", _editorTrainLine, typeof(GameObject), true, GUILayout.Width(100));
                if (editorTrainLine && editorTrainLine != _editorTrainLine)
                {
                    // 选中路线改变
                    Selection.activeGameObject = editorTrainLine;
                    _editorTrainLine = editorTrainLine;
                    string[] nameStrs = _editorTrainLine.name.Split("_");
                    if (nameStrs.Length == 3)
                    {
                        float.TryParse(nameStrs[2], out _editorWonderLineTime);
                    }
                    else
                    {
                        _editorWonderLineTime = 0;
                    }
                }
                GUILayout.Label("4.2、当前选中的列车路线时间(秒):", GUILayout.Width(300));
                float editorWonderLineTime2 = EditorGUILayout.FloatField( _editorWonderLineTime,  GUILayout.Width(100));
                if (editorWonderLineTime2 != _editorWonderLineTime && _editorTrainLine)
                {
                    _editorWonderLineTime = editorWonderLineTime2;
                    string[] nameStrs = _editorTrainLine.name.Split("_");
                    if (nameStrs.Length == 3)
                    {
                        _editorTrainLine.name = nameStrs[0] + "_" + nameStrs[1] + "_" + _editorWonderLineTime.ToString();
                    }
                    else
                    {
                        _editorTrainLine.name = _editorTrainLine.name + "_" + _editorWonderLineTime.ToString();
                    }
                }

                if (GUILayout.Button("5、导出所有列车路线"))
                {
                    if (_mapTrainLineRoot == null) return;
                    WonderLineDatas data = new WonderLineDatas();
                    data.lines = new List<WonderLineData>();
                    Vector3 tempV3 = new Vector3(0,0,0);
                    for (int i = 0; i < _mapTrainLineRoot.transform.childCount; i++)
                    {
                        Transform line = _mapTrainLineRoot.transform.GetChild(i);
                        WonderLineData lineData = new WonderLineData();
                        lineData.points = new List<Vector3>();
                        string[] wonderNames = line.name.Split("_");
                        int.TryParse(wonderNames[0], out lineData.startWonderId);
                        int.TryParse(wonderNames[1], out lineData.endWonderId);
                        int wonderLineTime = 0;
                        if (wonderNames.Length == 3)
                        {
                            int.TryParse(wonderNames[2], out wonderLineTime);
                        }
                        if(wonderLineTime == 0)
                        {
                            // 存在路线没有编辑时间
                            EditorUtility.DisplayDialog("提示", string.Format("导出路线错误 请设置路线{0}的时间", line.name), "ok");
                            return;
                        }
                        lineData.wonderLineTime = wonderLineTime;
                        for (int ii = 0; ii < line.transform.childCount; ii++)
                        {
                            Transform point = line.transform.GetChild(ii);
                            if (ii == 0)
                            {
                                int.TryParse(point.name, out lineData.startCrossIdx);
                                continue;
                            }
                            if (ii == line.transform.childCount - 1)
                            {
                                int.TryParse(point.name, out lineData.endCrossIdx);
                                continue;
                            }
                            tempV3.x = point.transform.position.x;
                            tempV3.z = point.transform.position.z;
                            lineData.points.Add(tempV3);
                        }

                        data.lines.Add(lineData);
                    }
                    data.points = new List<WonderPointData>();
                    for (int i = 0; i < _wonderCenterRoot.transform.childCount; i++)
                    {
                        Transform cross = _wonderCenterRoot.transform.GetChild(i);
                        WonderPointData crossData = new WonderPointData();
                        int.TryParse(cross.name, out crossData.id);
                        crossData.points = new List<Vector3>();
                        for (int ii = 0; ii < cross.transform.childCount; ii++)
                        {
                            Transform point = cross.transform.GetChild(ii);
                            tempV3.x = point.transform.position.x;
                            tempV3.z = point.transform.position.z;
                            crossData.points.Add(tempV3);
                        }
                        data.points.Add(crossData);
                    }

                    var ms = new MemoryStream();
                    new DataContractJsonSerializer(data.GetType()).WriteObject(ms, data);
                    var json = Encoding.UTF8.GetString(ms.ToArray());

                    string path = Application.dataPath + "/ResourcesAssets/Config/Data/";
                    string filePath = path + "mapTrainLineData.json";
                    if (!Directory.Exists(path))
                    {
                        Directory.CreateDirectory(path);
                    }

                    StreamWriter streamWriter = new StreamWriter(filePath);

                    streamWriter.Write(json.ToString());
                    streamWriter.Flush();
                    streamWriter.Close();

                    AssetDatabase.Refresh();

                    EditorUtility.DisplayDialog("提示", "导出路线成功 请将ResourcesAssets/Config/Data/mapTrainLineData.json 文件给到后端", "ok");
                }
                
            }

        }

        private void OnGUIofToolMapRoad()
        {
            DevelopmentToolAllRoadFoldOut = FoldoutReset(DevelopmentToolAllRoadFoldOut, "沙盘大地图道路相关");
            if (DevelopmentToolAllRoadFoldOut)
            {
                if (GUILayout.Button("加载当前地图"))
                {
                    // 关卡 奇观地块添加正式地表
                    if (GeneralMap._OpenWorldMapData(_worldMap, mapChunckEditorColor))
                    {
                        EditorUtility.DisplayDialog("通知", "加载成功", "ok");
                    }
                    else
                    {
                        EditorUtility.DisplayDialog("通知", "加载成功", "ok");
                    }
                    // 所有地图街区点生成
                    if (_worldMap)
                    {
                        if (mapObstructRoot) GameObject.DestroyImmediate(mapObstructRoot);
                        mapObstructRoot = new GameObject();
                        mapObstructRoot.transform.position = Vector3.zero;
                        mapObstructRoot.name = "地图街区点-根节点";
                        for (int i = 0; i < _worldMap.mapLODDatas.Count; i++)
                        {
                            var lodData = _worldMap.mapLODDatas[i];
                            if (lodData.lodDistance == 1)
                            {
                                for (int ii = 0; ii < lodData.mapChunckIds.Count; ii++)
                                {
                                    int chunckId = lodData.mapChunckIds[ii];
                                    GeneralMap.CreateChunckAlliancePoint(chunckId, ii, mapObstructRoot.transform);
                                }
                            }
                        }
                    }

                }
                _worldAllMap = (WorldMapData)EditorGUILayout.ObjectField("地图存储数据", _worldAllMap, typeof(WorldMapData), true);

                if (GUILayout.Button("裁切树(确保当前场景里面有阻挡组件的4车道)"))
                {
                    WorldMapData mapNewData = ScriptableObject.CreateInstance<WorldMapData>();
                    mapNewData.InitData(_worldAllMap);
                    List<MapChunckDeleateData> mapChunckDeleateDatas = new List<MapChunckDeleateData>();
                    GameObject mapHideItemRoot = new GameObject();
                    mapHideItemRoot.transform.position = Vector3.zero;
                    mapHideItemRoot.name = "地图装饰物裁切-根节点";
                    // 
                    for (int i = 0; i < mapNewData.mapLODDatas.Count; i++)
                    {
                        var lodData = mapNewData.mapLODDatas[i];
                        if (lodData.lodDistance == 1)
                        {
                            for (int ii = 0; ii < lodData.mapChunckIds.Count; ii++)
                            {
                                int chunckId = lodData.mapChunckIds[ii];
                                var deleteDate = GeneralMap.checkMapItemShowByRoad(chunckId, ii, mapHideItemRoot.transform);
                                mapChunckDeleateDatas.Add(deleteDate);
                            }
                        }
                    }
                    mapNewData.mapChunckDeleateDatas = Clone(mapChunckDeleateDatas); 
                    AssetDatabase.CreateAsset(mapNewData, GeneralMap.savePath + "/" + _generalMap.mapName + "_mapdata.asset");
                    AssetDatabase.Refresh();
                }

                if (GUILayout.Button("解析策划csv地图数据"))
                {
                    EditorCoroutines.StartCoroutine(CreateMapByCSV(), this);
                }

                _editorOverSeaShapeRoot = (GameObject)EditorGUILayout.ObjectField("海外点击范围导出根节点", _editorOverSeaShapeRoot, typeof(GameObject), true);
                if (GUILayout.Button("保持海外副本点击范围"))
                {
                    SaveOverSeaShapes();
                }
            }
        }

        private void OnGUIofToolChunck()
        {
            DevelopmentToolsFFoldOut = FoldoutReset(DevelopmentToolsFFoldOut, "地图块元素数据相关");
            if (DevelopmentToolsFFoldOut)
            {
                _worldChunck = (GameObject)EditorGUILayout.ObjectField("地图块保存节点", _worldChunck, typeof(GameObject), true);
                if (GUILayout.Button("保存该地图块"))
                {
                    if(_generalMap == null) _generalMap = new GeneralMap();
                    bool bExport = true;
                    // 发现性能分级没啥用 暂时舍弃
                    //if (mapChunckLevelObj == null)
                    //{
                    //    bExport = EditorUtility.DisplayDialog("提示", "当前不存在性能分级信息或者未编辑过，确认导出地图块数据吗？", "确认");

                    //}
                    if (bExport)
                    {
                        if(_generalMap.ExportMapChuckCfg(_worldChunck, MapChunckLevelMap))
                            EditorUtility.DisplayDialog("通知", "保存地图块成功！", "ok"); ;
                    }
                }
                if (GUILayout.Button("一键导出所有地图块"))
                {
                    if (_generalMap == null) _generalMap = new GeneralMap();
                    if (_generalMap.ExportAllMapChuckCfg())
                        EditorUtility.DisplayDialog("通知", "导出所有地图块成功！", "ok"); ;
                }
                GUI.enabled = true;
            }
        }


        private void OnGUIofToolPointAdorn()
        {
            DevelopmentToolsPointAdornFoldOut = FoldoutReset(DevelopmentToolsPointAdornFoldOut, "地图块装饰物数据相关");
            if (DevelopmentToolsPointAdornFoldOut)
            {
                _pointAdornChunck = (GameObject)EditorGUILayout.ObjectField("地图块节点", _pointAdornChunck, typeof(GameObject), true);
                if (_pointAdornChunck)
                {
                    UnityEditor.Tools.lockedLayers |= ~(1 << LayerMask.NameToLayer("MapPoint"));
                }
                else
                {
                    UnityEditor.Tools.lockedLayers = 0;
                }
                if (_pointAdornChunck == null) return;
                // 1.绑定编辑用根节点
                PointAdornRoot rootScript = _pointAdornChunck.GetComponentInChildren<PointAdornRoot>();
                if (rootScript == null)
                {
                    GameObject pointAdornLayer = new GameObject("LayerPointAdorn");
                    pointAdornLayer.transform.SetParent(_pointAdornChunck.transform);
                    _pointAdornRootScript = pointAdornLayer.AddComponent<PointAdornRoot>();
                }
                else if(_pointAdornRootScript == null || _pointAdornRootScript != rootScript)
                {
                    _pointAdornRootScript = rootScript;
                }
                //
                if (GUILayout.Button("加载地图出生点数据")) EditorCoroutines.StartCoroutine(LoadChunckPointData2(), this);
                if (GUILayout.Button("刷新地图出生点数据")) EditorCoroutines.StartCoroutine(UpdateChunckPointData2(), this);
                if (GUILayout.Button("随机一级装饰物")) LoadChunckPointData3();
                if (GUILayout.Button("随机二级装饰物")) LoadChunckPointData4();
                // 方法1
                GUILayout.Label("模组加载(适用于一级装饰物):", GUILayout.Width(300));
                GUILayout.BeginHorizontal();
                _pointAdornModol = (GameObject)EditorGUILayout.ObjectField("装饰物模组", _pointAdornModol, typeof(GameObject), true);
                _pointTagertObj = (GameObject)EditorGUILayout.ObjectField("目标出生点", _pointTagertObj, typeof(GameObject), true);
                if (GUILayout.Button("新建模组"))
                {
                    if (_pointAdornModol && _pointTagertObj)
                    {
                        GameObject modol = GameObject.Instantiate(_pointAdornModol, _pointAdornRootScript.transform);
                        modol.name = "MODOL<" + AssetDatabase.GetAssetPath(_pointAdornModol) + ">";
                        PointAdornModel adornScript = modol.GetOrAddComponent<PointAdornModel>();
                        adornScript.BindPoint(_pointTagertObj);
                    }
                }
                GUILayout.EndHorizontal();
                // 方法2
                GUILayout.Label("绑定加载(适用于多级装饰物):", GUILayout.Width(300));
                GUILayout.BeginHorizontal();
                //_pointAdornType = EditorGUILayout.Popup(_pointAdornType, adornType.ToArray(), GUILayout.Width(200));
                _pointAdornObj = (GameObject)EditorGUILayout.ObjectField("装饰物预制体", _pointAdornObj, typeof(GameObject), true);
                if (GUILayout.Button("新建装饰物"))
                {
                    GameObject[] selectObjs = Selection.gameObjects;
                    if (selectObjs.Length <= 1) return;// 
                    PointAdorn adornScript;
                    int adornType = -1;
                    if (_pointAdornObj)
                    {
                        GameObject adorn = GameObject.Instantiate(_pointAdornObj, _pointAdornRootScript.transform);
                        adorn.name = "OBJ<" + AssetDatabase.GetAssetPath(_pointAdornObj) + ">";
                        adornScript = adorn.GetOrAddComponent<PointAdorn>();
                        _pointAdornRootScript.AddAdorn(adornScript);
                    }
                    else
                    {
                        GameObject adorn = GameObject.CreatePrimitive(PrimitiveType.Cube);
                        adorn.name = "OBJ<0类型连接出生点装饰物>";
                        adorn.transform.parent = _pointAdornRootScript.transform;
                        adornScript = adorn.AddComponent<PointAdorn>();
                        _pointAdornRootScript.AddAdorn(adornScript);
                        adornType = 0;
                    }
                    adornScript.ClearObjs();
                    for (int i = 0; i < selectObjs.Length; i++)
                    {
                        GameObject obj = selectObjs[i];
                        if (obj != null) adornScript.AddObjs(obj);
                    }
                    adornScript.CheckPoints(adornType);
                }
                GUILayout.EndHorizontal();
                GUI.enabled = true;
            }
        }

        void wirteMapPointJson()
        {
            // ========================
            WorldMapData mapNewData = ScriptableObject.CreateInstance<WorldMapData>();
            mapNewData.InitData(_worldAllMap);
            mapNewData.mapChunckDeleatePoints = new List<int>();
            // ========================
            //WorldMapPointData pointNewData = ScriptableObject.CreateInstance<WorldMapPointData>();

            //
            if (mapPointRoot) DestroyImmediate(mapPointRoot);
            Dictionary<int, bool> mapPointInsetState = new Dictionary<int, bool>();
            MapData data = new MapData();
            data.mapWidth = _generalMap.wSize * _generalMap.tileWidth;
            data.mapHeight = _generalMap.hSize * _generalMap.tileHeight;
            data.areaWidth = _generalMap.tileWidth;
            data.areaHeight = _generalMap.tileHeight;
            data.areas = new List<MapAreaData>();
            Dictionary<string, MapAreaData> areaDatas = new Dictionary<string, MapAreaData>();
            if (GeneralMap.mapObj)
            {
                for (int i = 0; i < GeneralMap.mapObj.transform.childCount; i++)
                {
                    Transform tf = GeneralMap.mapObj.transform.GetChild(i);
                    int index1 = tf.gameObject.name.IndexOf('<');
                    int index2 = tf.gameObject.name.LastIndexOf('>');
                    string objpath = tf.gameObject.name.Substring(index1 + 1, index2 - index1 - 1);
                    string[] objpaths = objpath.Split('/');
                    string dataName = objpaths[objpaths.Count() - 1].Replace(".prefab", "") + "_pointData";

                    MapAreaData areaData0; // 未旋转和偏移的一块的点数据
                    MapAreaData areaData = new MapAreaData();// 真正导出的数据
                    areaData.cells = new List<MapCellData>();
         
                    if (areaDatas.ContainsKey(dataName))
                    {
                        areaData0 = areaDatas[dataName];
                    }
                    else
                    {
                        areaData0 = getMapAreaData(dataName);
                        areaDatas[dataName] = areaData0;
                    }
                    List<MapCellData> Cells = Clone<List<MapCellData>>(areaData0.cells);
                    Dictionary<int, int> cellId_localId = new Dictionary<int, int>();
                    if (areaData0.specials != null && areaData0.specials.Count > 0)
                    {
                        areaData.specials = new List<MapSpecial>();
                    }
                    // 设置全局变量
                    areaData.areaId = i;
                    areaData.resLevel = 0;
                    for (int ii = 0; ii < Cells.Count; ii++)
                    {
                        // 现在tf可能存在旋转
                        float r = tf.transform.eulerAngles.y;
                        if (r < 0)
                        {
                            r += 360;
                        }
                        int rotation = (int)math.ceil(r / 90);
                        MapCellData cellData = Cells[ii];

                        Vector3 curPos = GeneralMap.GetPosByAngle(new Vector3(cellData.x, 0, cellData.z), rotation);
                        cellData.x = curPos.x;
                        cellData.z = curPos.z;

                        cellData.x += tf.position.x;
                        cellData.z += tf.position.z;
                        int localId = cellData.cellId;
                        cellData.cellId = GetMapPointPosIdx((int)(cellData.x), (int)(cellData.z)); // 陆地的为1200尺寸 海外为1380尺寸并且为负数 -为了不影响线上
                        cellId_localId[cellData.cellId] = localId;
                        if (mapPointInsetState.ContainsKey(cellData.cellId) == false)
                        {
                            mapPointInsetState[cellData.cellId] = true;
                        }
                        else
                        {
                            areaData.cells.RemoveAt(ii);
                            Debug.LogError("[josn] 导出数据重复 ===================== " + string.Format("[{3}] => ({0},{1}) : [{2}]", cellData.x, cellData.z, cellData.cellId, areaData.areaId));
                            ShowNotification(new GUIContent("注意!导出的点数据有重复！！！！！！！"));
                            return;
                        }

                        // 出生点需要检测和道路的碰撞
                        bool hide = judgeMapPointHideByRoad(new Vector3(cellData.x,0, cellData.z), cellData.type);

                        if (hide)
                        {
                            // 向大地图数据中写入出生点删除记录
                            mapNewData.mapChunckDeleatePoints.Add(cellData.cellId);
                            continue;
                        }
                        else
                        {
                            if (cellData.type == (int)WorldEntry.MapPointType.E_EditorResPoint) // 舍弃 有时候真不知道策划在想什么
                            {
                                // 如果是E_EditorResPoint 需要将该点拆分成4个出生点导出给服务器 
                                // 检查该点是否位于1x1的格子中心
                                //float maxOffset = 0.5f - WorldEntry.resPointOffset;
                                //Vector3 pos = new Vector3(cellData.x,0, cellData.z);
                                //float center_x = (pos.x > 0) ? ((int)pos.x + 0.5f) : ((int)pos.x - 0.5f);
                                //float center_y = (pos.z > 0) ? ((int)pos.z + 0.5f) : ((int)pos.z - 0.5f);
                                //bool bCenterX = MathF.Abs(pos.x - center_x) < maxOffset;
                                //bool bCenterY = MathF.Abs(pos.z - center_y) < maxOffset;
                                //if (!(bCenterX && bCenterY))
                                //{
                                //    Debug.LogError("[josn] 导出数据错误 ===================== " + string.Format("[{3}] => ({0},{1}) : [{2}]", cellData.x, cellData.z, cellData.cellId, areaData.areaId));
                                //    ShowNotification(new GUIContent("注意!导出的点数据有错误！！！！！！！资源点的位置不对 请检查"));
                                //    return;
                                //}

                                //// 将该点拆分成4个资源点 偏移0.45
                                //for (int offset_x = -1; offset_x <= 1; offset_x++)
                                //{
                                //    for (int offset_y = -1; offset_y <= 1; offset_y++)
                                //    {
                                //        if(offset_x * offset_y != 0)
                                //        {
                                //            MapCellData cellDataRes = new MapCellData();
                                //            int offsetIdx = offset_x + 1 + (offset_y + 1) * 2;
                                //            cellDataRes.cellId = cellData.cellId * 10 + offsetIdx + 10000000;
                                //            cellDataRes.x = cellData.x + offset_x * WorldEntry.resPointOffset;
                                //            cellDataRes.z = cellData.z + offset_y * WorldEntry.resPointOffset;
                                //            cellDataRes.type = (int)WorldEntry.MapPointType.E_Res;
                                //            areaData.cells.Add(cellDataRes);
                                //            if (bShowMapPoint) addMapPoint(cellDataRes.x, cellDataRes.z, cellDataRes.type, cellDataRes.cellId);
                                //            if (mapPointInsetState.ContainsKey(cellDataRes.cellId) == false)
                                //            {
                                //                mapPointInsetState[cellDataRes.cellId] = true;
                                //            }
                                //            else
                                //            {
                                //                Debug.LogError("[josn] 导出资源点数据重复 ===================== " + string.Format("[{3}] => ({0},{1}) : [{2}]", cellDataRes.x, cellDataRes.z, cellDataRes.cellId, cellDataRes.type));
                                //                ShowNotification(new GUIContent("注意!导出的资源点数据有重复！！！！！！！"));
                                //                return;
                                //            }
                                //        }   
                                //    }
                                //}
                                
                            }
                            else
                            { 
                                areaData.cells.Add(cellData);
                                // 检查点位特殊配置
                                if (cellId_localId.ContainsKey(cellData.cellId) && areaData0.specials != null)
                                {
                                    int _localId = cellId_localId[cellData.cellId];
                                    for (int iii = 0; iii < areaData0.specials.Count; iii++)
                                    {
                                        if (areaData0.specials[iii].cellId == _localId) // areaData0中的cellId 就是localId
                                        {
                                            MapSpecial special = new MapSpecial();
                                            special.cellId = cellData.cellId;
                                            special.specialCfgs = areaData0.specials[iii].specialCfgs;
                                            areaData.specials.Add(special);
                                        }
                                    }
                                }
                                if (bShowMapPoint) addMapPoint(cellData.x, cellData.z, cellData.type, cellData.cellId);
                            }
                            // 添加客户端点id-pos映射 后续需要优化
                            //if (WorldEntry.MapShowAdornPointType.Contains(cellData.type))
                            //{
                            //    MapPointInfo pointInfo = new MapPointInfo(cellData.cellId, new Vector3(cellData.x, 0, cellData.z));
                            //    pointNewData.AddPoint(pointInfo);
                            //}
                        }
                      
                     
                        //Debug.Log("[josn] 导出数据 ===================== " + string.Format("[{3}] => ({0},{1}) : [{2}]", areaData.cells[ii].x, areaData.cells[ii].z, areaData.cells[ii].cellId, areaData.areaId));
                   
                    }
                    data.areas.Add(areaData);

                }
            }
            //
            var ms = new MemoryStream();
            new DataContractJsonSerializer(data.GetType()).WriteObject(ms, data);
            var json = Encoding.UTF8.GetString(ms.ToArray());

            string path = Application.dataPath + "/ResourcesAssets/Config/Data/";
            string filePath = path + "mapPointData.json";
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }

            StreamWriter streamWriter = new StreamWriter(filePath);

            streamWriter.Write(json.ToString());
            streamWriter.Flush();
            streamWriter.Close();

            AssetDatabase.Refresh();

            // =========================================
            AssetDatabase.CreateAsset(mapNewData, GeneralMap.savePath + "/" + _generalMap.mapName + "_mapdata.asset");
            //AssetDatabase.CreateAsset(pointNewData, GeneralMap.savePath + "/client_pointData.asset");
            AssetDatabase.Refresh();
            //

            Debug.Log("导出地图打点数据成功：" + filePath);
        }

        // 通过世界坐标 获取cellId 陆地使用1200尺寸计算的正数 海外使用1380计算的负数 -为了不让线上数据受影响 淦！！
        private int GetMapPointPosIdx(int x, int y)
        {
            bool inWorld = WorldMapConfigData.CheckPosInWorld(x, y);
            int idx = 0;
            int tileSize = WorldEntry.m_iTileSize;
            int tileX = x / tileSize;
            int tileY = y / tileSize;
            int tileLineNum = WorldEntry.m_mapLandSize / tileSize;
            if (!inWorld)
            {
                tileLineNum += WorldEntry.m_overSeaSize / tileSize;
            }
            int tileIdx = tileX + tileY * tileLineNum;
            int posIdx = x - tileX * tileSize + (y - tileY * tileSize) * tileSize;
            idx = tileIdx * 1000 + posIdx;
            if (!inWorld)
            {
                idx *= -1;
            }
            return idx;
        }

        private int GetMapPointResPosIdx(float x, float y)
        {
            int int_x = (int)x; // 整数x 
            int int_y = (int)y; // 整数y
            int idx = 0;
            int tileSize = WorldEntry.m_iTileSize;
            int tileX = (int)x / tileSize;
            int tileY = (int)y / tileSize;
            int tileLineNum = WorldEntry.m_mapSize / tileSize;
            int tileIdx = tileX + tileY * tileLineNum;
            int posIdx = int_x - tileX * tileSize + (int_y - tileY * tileSize) * tileSize;
            idx = tileIdx * 1000 + posIdx;
            // 计算出资源点位于中心点的偏移
            float offset = WorldEntry.resPointOffset;// 0.39f
            float center_x = int_x + offset;
            float offset_x = (x - center_x) / offset;
            float center_y = int_y + offset;
            float offset_y = (y - center_y) / offset;
            float offset_idx = (offset_x + 1) + (offset_y + 1) * 2; // 2x2坐标系 一个资源点会拆分成4个 
            idx = idx * 10 + (int)offset_idx;//idx 最大值为 1599 900
            return idx;
        }

        void addMapPoint(float x,float z,int type, int cellId)
        {
            if (mapPointRoot == null)
            {
                mapPointRoot = new GameObject();
            }
            GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
            cube.transform.localScale = new Vector3(1.3f, 0, 1.3f);
            cube.transform.position = new Vector3(x, 0, z);
            cube.gameObject.name = type.ToString() + "_" + cellId.ToString();
            cube.transform.SetParent(mapPointRoot.transform,false);
        }

        MapAreaData getMapAreaData(string cfgName)
        {
            MapAreaData area = new MapAreaData();
            area.cells = new List<MapCellData>();
            TextAsset content = AssetDatabase.LoadAssetAtPath<TextAsset>(savePointPath + cfgName + ".txt");
            if (content != null && content.text != null && content.text.Length > 0)
            {
                var csvText = content.text.Trim();
                var lines = csvText.Split(new char[1] { '\n' }, StringSplitOptions.RemoveEmptyEntries);

                for (int i = 2; i < lines.Length; i++)
                {
                    var l = lines[i];
                    var data = l.Split(',');

                    if (data.Length == 4)
                    {
                        MapCellData celldata = new MapCellData();
                        int.TryParse(data[0], out celldata.cellId);
                        float.TryParse(data[1], out celldata.x);
                        float.TryParse(data[2], out celldata.z);
                        int.TryParse(data[3], out celldata.type);
                        area.cells.Add(celldata);
                    }
                }
            }

            content = AssetDatabase.LoadAssetAtPath<TextAsset>(savePointPath + cfgName + "_special.txt");
            if (content != null && content.text != null && content.text.Length > 0)
            {
                area.specials = new List<MapSpecial>();
                var csvText = content.text.Trim();
                var lines = csvText.Split(new char[1] { '\n' }, StringSplitOptions.RemoveEmptyEntries);

                for (int i = 2; i < lines.Length; i++)
                {
                    var l = lines[i];
                    var data = l.Split(',');

                    if (data.Length == 2)
                    {
                        int.TryParse(data[0], out int localId);
                        string cfgs = data[1];
                        MapSpecial special = new MapSpecial();
                        special.cellId = localId;// 这里的是本地坐标 不是真正的cellId
                        string[] strCfgs = cfgs.Split("|");
                        special.specialCfgs = new List<int>();
                        for (int ii = 0; ii < strCfgs.Length - 1; ii++)
                        {
                            int.TryParse(strCfgs[ii], out int specialCfg);
                            special.specialCfgs.Add(specialCfg);
                        }
                        area.specials.Add(special);
                    }
                }
            }

            return area;
        }

        void ListAdd<T>(ref List<T> dest, List<T> ori)
        {
            if (dest == null || ori == null) return;
            for (int i = 0;i < ori.Count; i++)
            {
                dest.Add(ori[i]);
            }
        }

        private void SelectMapSaveFolder()
        {
            string path = EditorUtility.OpenFolderPanel("选择地图存储路径", "", "");
            if (path.Length > 0)
            {

                GeneralMap.savePath = path;
                EditorUtility.FocusProjectWindow();
            }
        }

        public void ResetWorldMapData(WorldMapData mapdata1)
        {
            //WorldMapData mapData = ScriptableObject.CreateInstance<WorldMapData>();
            //mapData.mapWidth = mapdata1.mapWidth;
            //mapData.mapHeight = mapdata1.mapHeight;
            //mapData.resourceDatas = mapdata1.resourceDatas;
            //mapData.mapLayers = mapdata1.mapLayers;
            //mapData.dicResourceDatas = mapdata1.dicResourceDatas;
            //// 这里写一切程序想修改文件的方法
            //for (int i = 0;i < mapData.mapLayers.Count;i++)
            //{
            //    var mapLayer = mapData.mapLayers[i];
            //    if (mapLayer.layerID == WorldEntry.TREE_LAYER_ID)
            //    {
            //        for (int ii = 0; ii < mapData.mapLayers[i].mapLODDatas.Count; ii++)
            //        {
            //            MapLODData data = mapData.mapLayers[i].mapLODDatas[ii];
            //            for (int iii = 0; iii < data.chunckData.properties.Count; iii++)
            //            {
            //                data.chunckData.properties[iii].level = 1;
            //            }
            //        }
            //    }
            //}
            ////
            //AssetDatabase.CreateAsset(mapData, GeneralMap.savePath + "/" + mapdata1.name + ".asset");
            //AssetDatabase.Refresh();
        }

        public static bool FoldoutReset(bool foldout, string content)
        {
            Rect rect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight, EditorStyles.foldout);

            EditorGUI.DrawRect(EditorGUI.IndentedRect(rect), new Color(0,0,0,0.05f));

            Rect foldoutRect = rect;
            foldoutRect.width = EditorGUIUtility.singleLineHeight;

            foldout = EditorGUI.Foldout(rect, foldout, "", true);

            rect.x += EditorGUIUtility.singleLineHeight;
            EditorGUI.LabelField(rect, content, EditorStyles.boldLabel);
            return foldout;
        }

        // 获得鼠标点击到地图上(tileWidth,tileHeight)坐标系下位置
        Vector2 GetRaycastPos(Vector3 mousePos, out bool bHit)
        {
            bHit = false;
            Vector2 pos = new Vector2(-1,-1);
            RaycastHit hit;
            Ray ray = HandleUtility.GUIPointToWorldRay(mousePos);

            //hit.point 就是投射到地图上面的坐标 对应 x-z坐标系 到 x-y坐标系
            RaycastHit[] hits = Physics.RaycastAll(ray);
            for (int i = 0;i < hits.Length; i++)
            {
                RaycastHit res = hits[i];
                if (res.transform.name == "Plane")
                {
                    bHit = true;
                    pos = new Vector2(Mathf.Floor(res.point.x / _generalMap.tileWidth), Mathf.Floor(res.point.z / _generalMap.tileHeight));
                }
            }

            return pos;
        }

        // 将地图尺寸10x10坐标系下坐标转换成迷雾尺寸10x10坐标系下坐标
        Vector2Int GetFogPos(int x, int y)
        {
            int offsetIdx = (int)((MapFofLineNum - _generalMap.wSize) / 2);
            Vector2Int fogPos = new Vector2Int(x + offsetIdx, y + offsetIdx);
            return fogPos;
        }
        Vector2 GetMapPosByFogPoint(int fog_x,int fog_y)
        {
            int offsetIdx = (int)((MapFofLineNum - _generalMap.wSize) / 2);
            Vector2 fogPos = new Vector2(fog_x - offsetIdx, fog_y - offsetIdx);
            fogPos = fogPos * MapFogSize;
            return fogPos;
        }
        void SceneGUIbefore(SceneView sceneView)
        {
            // 交通编辑触摸事件
            OnTrafficEditorEventEnd();
            // 区域编辑触摸结束事件
            OnMapAreaEditorEventEnd();
        }
        private void SceneGUI(SceneView sceneView)
        {
            // 交通编辑触摸事件
            OnTrafficEditorEvent();
            // 区域编辑触摸事件
            OnMapAreaEditorEvent();
        }

        void DrawFunc()
        {
            // 绘制地图区域信息
            DrawMapAreaInfo();
            // 地图块交通编辑
            if (DevelopmentToolsGFoldOut)
            {
                Color oldColor = Gizmos.color;
                // 编辑状态 + 存在拖拽起始点
                Color trafficRed = Color.red;
                trafficRed.a = 0.5f;
                if (trafficDragObj)
                {
                    Gizmos.color = trafficRed;
                    if (trafficDragEndObj)
                    {
                        Gizmos.DrawLine(trafficDragObj.transform.position, trafficDragEndObj.transform.position);
                    }
                    else
                    {
                        Gizmos.DrawLine(trafficDragObj.transform.position, GetMousePosToScene());
                    }
                }


                if (_curEditorTrafficLine.Count > 0)
                {
                    Gizmos.color = trafficRed;
                    for (int i = 0; i < _curEditorTrafficLine.Count; i++)
                    {
                        TrafficTempLineInfo info = _curEditorTrafficLine[i];
                        Gizmos.DrawLine(info.start.transform.position, info.end.transform.position);
                    }
                }
                Color trafficBlue = Color.blue;
                trafficBlue.a = 0.5f;
                if (_curTrafficLineDatas.Count > 0)
                {
                    Gizmos.color = trafficBlue;
                    for (int i = 0; i < _curTrafficLineDatas.Count; i++)
                    {
                        if (_curTrafficLineShow[i])
                        {
                            List<TrafficLineData> datas = _curTrafficLineDatas[i];
                            for (int ii = 0;ii < datas.Count - 1;ii++)
                            {
                                TrafficLineData data1 = datas[ii];
                                TrafficNode node1 = GetTrafficNode(data1.nodeId);
                                TrafficPoint obj1 = node1.GetTrafficPoint(data1.pointId);

                                TrafficLineData data2 = datas[ii + 1];
                                TrafficNode node2 = GetTrafficNode(data2.nodeId);
                                TrafficPoint obj2 = node2.GetTrafficPoint(data2.pointId);

                                // 检查 1 -> 2 的中间点
                                Transform tfRoad = obj1.transform.Find(data2.pointId.ToString());
                                if (tfRoad != null)
                                {
                                    Vector3 curPos = obj1.transform.position;
                                    for (int iii = 0; iii < tfRoad.childCount; iii++)
                                    {
                                        Vector3 nextPos = tfRoad.GetChild(iii).position;
                                        Gizmos.DrawLine(curPos, nextPos);
                                        curPos = nextPos;
                                    }
                                    Gizmos.DrawLine(curPos, obj2.transform.position);
                                }
                                else
                                {
                                    Gizmos.DrawLine(obj1.transform.position, obj2.transform.position);
                                }
                            }
                        }
                    }
                }

                Gizmos.color = oldColor;
            }
        }

        void SetDraw(bool bClear = false)
        {
            GameObject go = GameObject.Find("GizmosRoot");
            if (go == null)
            {
                if (bClear) return;
                go = new GameObject();
                go.AddComponent<GizmosRoot>();
                go.name = "GizmosRoot";
            }
            GizmosRoot gr = go.GetComponent<GizmosRoot>();

            if (gr == null)
            {
                gr = go.AddComponent<GizmosRoot>();
            }

            if (bClear == false)
            {
                gr.SetDrawFunc1(DrawFunc);
            }
            else
            {
                gr.SetDrawFunc1(null);
            }
        }

        // 策划csv文件导入格式
        public struct chunckCSVDta
        {
            public int idx;
            public int chunckId;

            public int offset_x;
            public int offset_y;

            public int overSeaType;
            public int overSeaUid;
        }

        IEnumerator CreateMapByCSV()
        {
            // 选择默认路径 打开CSV文件
            string csvPath = "Assets/ResourcesAssets/World/mapdata/";
            string path = EditorUtility.OpenFilePanel("地图csv数据导入", csvPath, "txt");
            path = GetPath(path);

            if (!string.IsNullOrEmpty(path))
            {
                TextAsset content = AssetDatabase.LoadAssetAtPath<TextAsset>(path);
                if (content != null && content.text != null && content.text.Length > 0)
                {
                    // 解析csv数据
                    var csvText = content.text.Trim();
                    string[] lines = csvText.Split(new char[1] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
                    List<chunckCSVDta> datas = new List<chunckCSVDta>();
                    List<chunckCSVDta> overSeaDatas = new List<chunckCSVDta>();
                    int lineNum = WorldEntry.m_mapSize / WorldEntry.m_iTileSize;

                    for (int i = 0; i < lines.Length; i++)
                    {
                        chunckCSVDta data = new chunckCSVDta();
                        string line = lines[i];
                        line = line.Replace(";", "");
                        line = line.Replace("\r", "");
                        string[] infos = line.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                        int.TryParse(infos[0], out int data_x); // 地图块左下角世界坐标 x
                        int.TryParse(infos[1], out int data_y);
                        int.TryParse(infos[2], out int chunckId);// 地图块id
                        int.TryParse(infos[3], out int overSeaType); // 海外副本类型 0无效值
                        int.TryParse(infos[4], out int overSeaUid); // 海外副本uid 同一类型只能有一个
                        data.idx = (data_x / WorldEntry.m_iTileSize) + (data_y / WorldEntry.m_iTileSize) * lineNum;
                        data.chunckId = chunckId;

                        if (data_x >= 0 && data_y >= 0 && data_x < WorldEntry.m_mapSize && data_y < WorldEntry.m_mapSize) // 
                        {
                            datas.Add(data);
                        }
                        if (data_x < 0 || data_y < 0 || data_x >= WorldEntry.m_mapLandSize || data_y >= WorldEntry.m_mapLandSize) // 装饰地图 和 海外地图 记录在overSeaDatas
                        {
                            data.idx = 0;
                            data.offset_x = data_x / WorldEntry.m_iTileSize;
                            data.offset_y = data_y / WorldEntry.m_iTileSize;

                            data.overSeaType = overSeaType;
                            data.overSeaUid = overSeaUid;
                            overSeaDatas.Add(data);
                        }
                    }
                    datas.Sort((a, b) =>
                    {
                        return a.idx - b.idx;
                    });


                    // 1 创建数据
                    var mapData = ScriptableObject.CreateInstance<WorldMapData>();
                    mapData.mapWidth = WorldEntry.m_mapSize;
                    mapData.mapHeight = WorldEntry.m_mapSize;
                    mapData.name = "sandbox_lod1";

                    // 2 创建lod数据
                    MapLODData lodData = new MapLODData()
                    {
                        lodDistance = 1,
                        tileSize = WorldEntry.m_iTileSize,
                    };

                    // 3 导出所有地图块
                    for (int i = 0; i < datas.Count; i++)
                    {
                        lodData.AddMapChunckId(datas[i].chunckId);
                    }
                    for (int i = 0; i < overSeaDatas.Count; i++)
                    {
                        chunckCSVDta edge = overSeaDatas[i];
                        lodData.AddMapOverSeaChunck(edge.offset_x, edge.offset_y, edge.chunckId, edge.overSeaType, edge.overSeaUid);
                    }
                    mapData.AddLODData(lodData);
                    string dataPath = "Assets/ResourcesAssets/World/mapdata/sandbox_lod1_mapdata_new.asset";

                    AssetDatabase.CreateAsset(mapData, dataPath);
                    ShowNotification(new GUIContent("地图CSV文件导出成功!"));
                }
                yield return null;
            }
        }

        void SaveOverSeaShapes()
        {
            if (_worldMap && _editorOverSeaShapeRoot)
            {
                WorldMapData mapNewData = ScriptableObject.CreateInstance<WorldMapData>();
                mapNewData.InitData(_worldMap);
                mapNewData.mapOverSeaShapeInfos = new List<OverSeaShapeInfo>();
                for (int i = 0; i < _editorOverSeaShapeRoot.transform.childCount; i++)
                {
                    ShapeCreator shapeCreator = _editorOverSeaShapeRoot.transform.GetChild(i).GetComponent<ShapeCreator>();
                    if (shapeCreator)
                    {
                        OverSeaShapeInfo info = new OverSeaShapeInfo(shapeCreator.gameObject.name, shapeCreator.getShapePoint(0));
                        mapNewData.mapOverSeaShapeInfos.Add(info);
                    }
                }

                AssetDatabase.CreateAsset(mapNewData, GeneralMap.savePath + "/" + _generalMap.mapName + "_mapdata.asset");
                AssetDatabase.Refresh();
            }
            else
            { 
                //
            }
        }

        #region 地图区域相关

        private void OnGUIofToolMapArea()
        {
            DevelopmentToolsEFoldOut = FoldoutReset(DevelopmentToolsEFoldOut, "地图区域编辑相关");
            if (DevelopmentToolsEFoldOut)
            {
                InitMapAreaEidor();
                bMapAreaEditor = false;
                EditorGUILayout.BeginVertical();

                for (int i = (int)mapAreaEditorType.E_AREA; i <= (int)mapAreaEditorType.E_Monster_Smuggle_Level; i++)
                {
                    mapAreaEditorType type = (mapAreaEditorType)i;
                    EditorGUILayout.BeginHorizontal();
                    GUILayout.Label(mapAreaInfoEditorName[type], GUILayout.Width(100));
                    mapAreaInfoEditorState[type] = GUILayout.Toggle(mapAreaInfoEditorState[type], "", GUILayout.Width(20));
                    bool fogEditorState = mapAreaInfoEditorState[mapAreaEditorType.E_FOGID];
                    if (MapFogEditorRoot && MapFogEditorRoot.activeSelf != fogEditorState)
                    {
                        MapFogEditorRoot.SetActive(fogEditorState);
                    }

                    bMapAreaEditor = bMapAreaEditor || mapAreaInfoEditorState[type];
                    int level = mapAreaInfoEditorLevel[type];
                    string sLevel = GUILayout.TextField(level.ToString(),GUILayout.Width(40));
                    int.TryParse(sLevel, out level);
                    // 检查等级
                    if (type == mapAreaEditorType.E_FOGID)
                    {
                        mapAreaInfoEditorLevel[type] = level; // 迷雾id不检查
                    }
                    else if (level < 0 || (level > 0 && level > mapAreaInfoEditorColor[type].Count))
                    {
                        ShowNotification(new GUIContent("所填" + mapAreaInfoEditorName[type] + "大于预设等级，如需增加等级，请找对应前端添加"));
                    }
                    else
                    {
                        mapAreaInfoEditorLevel[type] = level;
                    }
                    EditorGUILayout.EndHorizontal();
                }
                EditorGUILayout.EndVertical();
                bMapAreaEditor = bMapAreaEditor && DevelopmentToolsEFoldOut;

                if (bMapAreaEditor && mapAreaEditorRoot == null) StartMapAreaEditor();
                if (!bMapAreaEditor && mapAreaEditorRoot != null) EndMapAreaEditor();
                if (GUILayout.Button("输出当前区域编辑数据统计"))
                {
                    logMapAreaDara();
                }
                if (GUILayout.Button("输出当前资源等级"))
                {
                    outResLevelImage();
                }
                if (GUILayout.Button("保存区域数据"))
                {
                    wirteMapAreaJson();
                }
                if (GUILayout.Button("打开沙盘面数据文件"))
                {
                    string path = EditorUtility.OpenFilePanel("地图区域信息路径", Application.dataPath + "/ResourcesAssets/World/mapdata/", "");
                    if (path.Length > 0)
                    {
                        EditorUtility.FocusProjectWindow();
                        readMapAreaJson(path);
                    }
                }
                GUI.enabled = true;
            }
        }

        void InitMapAreaEidor()
        {
            if (bMapAreaEditorInit) return;
            bMapAreaEditorInit = true;

            // 判断一下当前筛子的大小是否正确
            if (_generalMap.wSize != 120 || _generalMap.hSize != 120 || _generalMap.tileWidth != 10 || _generalMap.tileHeight != 10 || _generalMap.Size != 10)
            {
                ShowNotification(new GUIContent("地图区域的刷子大小要注意！！！！"));
            }

           
            mapAreaInfos[mapAreaEditorType.E_RESLEVEL] = new Dictionary<int, int>();
            mapAreaInfos[mapAreaEditorType.E_AREA] = new Dictionary<int, int>();
            mapAreaInfos[mapAreaEditorType.E_CITY] = new Dictionary<int, int>();
            mapAreaInfos[mapAreaEditorType.E_MONSTER] = new Dictionary<int, int>();
            mapAreaInfos[mapAreaEditorType.E_FOGID] = new Dictionary<int, int>();
            mapAreaInfos[mapAreaEditorType.E_Monster_Smuggle_Level] = new Dictionary<int, int>();
            mapFogInfos = new Dictionary<int, MapFogRunDta>();
        }

        void StartMapAreaEditor()
        {
            // 地图区域地面检测添加
            if (mapAreaEditorRoot == null)
            {
                mapAreaEditorRoot = GameObject.CreatePrimitive(PrimitiveType.Cube);
                MeshRenderer render = mapAreaEditorRoot.GetComponent<MeshRenderer>();
                render.enabled = false;
                Vector3 mapSize = new Vector3(_generalMap.wSize * _generalMap.tileWidth, 0, _generalMap.hSize * _generalMap.tileHeight);
                mapAreaEditorRoot.transform.localScale = new Vector3(MapFogOutSize,0, MapFogOutSize);
                mapAreaEditorRoot.transform.position = mapSize * 0.5f;
                mapAreaEditorRoot.name = "Plane";
                mapAreaEditorRoot.layer = LayerMask.NameToLayer("MapPoint");
                UnityEditor.Tools.lockedLayers |= ~(1 << LayerMask.NameToLayer("MapPoint"));
            }
      
            mapAreaEditorStart = new Vector2(-1, -1);
        }

        void EndMapAreaEditor()
        {
            // 地图区域地面检测添加
            if (mapAreaEditorRoot)
            {
                DestroyImmediate(mapAreaEditorRoot);
            }
        
            mapAreaEditorStart = new Vector2(-1, -1);
            bMapAreaEditor = false;
            UnityEditor.Tools.lockedLayers = 0;
        }

        void OnMapAreaEditorEvent()
        {
            if (!bMapAreaEditor) return;
            if (Event.current.button == 0)
            {
                if (Event.current.type == EventType.MouseDown)
                {
                    // 开始拖动
                    mapAreaEditorStart = GetRaycastPos(Event.current.mousePosition, out bool bHit);
                    bMouseMove = bHit;
                }
            }
            else
            {
                bMouseMove = false;
            }
            if (Event.current.type == EventType.MouseLeaveWindow)
            {
                bMouseMove = false;
            }

            if (bMouseMove)
            {
                Vector2 resEditorEnd = GetRaycastPos(Event.current.mousePosition, out bool bHit);
                if (!bHit) return;
                int min_x = Mathf.Min((int)mapAreaEditorStart.x, (int)resEditorEnd.x);
                int max_x = Mathf.Max((int)mapAreaEditorStart.x, (int)resEditorEnd.x);
                int min_y = Mathf.Min((int)mapAreaEditorStart.y, (int)resEditorEnd.y);
                int max_y = Mathf.Max((int)mapAreaEditorStart.y, (int)resEditorEnd.y);
                int fogWorldSize = WorldEntry.m_mapSize / 10;
                for (int x = min_x; x <= max_x; x++)
                {
                    for (int y = min_y; y <= max_y; y++)
                    {
                        if ((x < 0 || y < 0 || x >= fogWorldSize || y >= fogWorldSize))
                        {
                            mapAreaEditorType type = mapAreaEditorType.E_FOGID;
                            if (mapAreaInfoEditorState[type])
                            {
                                int level = mapAreaInfoEditorLevel[type];
                                // 将坐标转换到迷雾坐标系下
                                Vector2Int fogPos = GetFogPos(x, y);
                                MapFogRunDta fogData = new MapFogRunDta();
                                fogData.exploreId = level;
                                fogData.indexFog = fogPos.x + fogPos.y * MapFofLineNum;
                                fogData.indexFog_x = fogPos.x;
                                fogData.indexFog_y = fogPos.y;
                                fogData.indexMap_x = x;
                                fogData.indexMap_y = y;
                                // 将该数据填充到mapFogInfos
                                mapFogInfos[fogData.indexFog] = fogData;
                            }
                        }
                        else
                        {
                            int idx = x + y * _generalMap.wSize;
                            for (int i = (int)mapAreaEditorType.E_AREA; i <= (int)mapAreaEditorType.E_Monster_Smuggle_Level; i++)
                            {
                                mapAreaEditorType type = (mapAreaEditorType)i;
                                if (mapAreaInfoEditorState[type])
                                {
                                    int level = mapAreaInfoEditorLevel[type];
                                    if (type == mapAreaEditorType.E_FOGID)
                                    {
                                        // 世界坐标内的迷雾还是按照陆地尺寸
                                        idx = x + y * _generalMap.wSize;
                                    }
                                    mapAreaInfos[type][idx] = level;
                                }
                            }
                        }
                    }
                }
            }
        }

        void OnMapAreaEditorEventEnd()
        {
            if (!bMapAreaEditor) return;
            if (Event.current.button == 0)
            {
                if (Event.current.type == EventType.MouseUp)
                {
                    bMouseMove = false;
                }
            }
        }

        void outResLevelImage()
        {
            // 创建120x120 的2d图片 边界166 - 120 = 46
            int mapSize0 = WorldEntry.m_mapSize / 10;
            int mapSize = WorldEntry.m_mapLandSize / 10;
            int imgSize = mapSize + 46; // 46是周围留白
            Texture2D tex = new Texture2D(imgSize, imgSize);

            if (mapAreaInfos == null)
            {
                return;
            }
            // 按照最低层级插入边界
            Color c = mapResLevelColors[1];
            for (int x = 0; x < imgSize; x++)
            {
                for (int y = 0; y < imgSize; y++)
                {
                    if (!(x >=23 && x < mapSize && y >= 23 && y < mapSize))
                    {
                        tex.SetPixel(x, y, c);
                    }
                }
            }


            Dictionary<int, int> resInfos = mapAreaInfos[mapAreaEditorType.E_RESLEVEL];
            foreach (int idx in resInfos.Keys)
            {
                int level = resInfos[idx];
                int x = idx % mapSize0 + 23;
                int y = idx / mapSize0 + 23;
                if (level < 0) level = 0;
                Color color = mapResLevelColors[level];
                tex.SetPixel(x, y, color);
            }
            tex.Apply();
            // 保存该图片
            File.WriteAllBytes("Assets/Arts/World/sandtable/textures/Map/mapResLevel.png", tex.EncodeToPNG());
            AssetDatabase.Refresh();
        }

        void logMapAreaDara()
        {
            foreach (mapAreaEditorType key in mapAreaInfos.Keys)
            {
                string name = mapAreaInfoEditorName[key];
                Dictionary<int, int> areaInfo = mapAreaInfos[key];
                Dictionary<int, int> areaNum = new Dictionary<int, int>();
                foreach (int level in areaInfo.Values)
                {
                    int levelNum = 0;
                    areaNum.TryGetValue(level, out levelNum);
                    levelNum++;
                    areaNum[level] = levelNum;
                }
                // 打印对应信息
                Debug.Log(string.Format("========================== {0}的统计信息 ==========================",name));
                foreach (int level in areaNum.Keys)
                {
                    int num = areaNum[level];
                    Debug.Log(string.Format("{0}的{1}的当前数量:{2} ==========================", name,level,num));
                }
            }
        }

        void wirteMapAreaJson()
        {
            Dictionary<int, int> debugFogNum = new Dictionary<int, int>(); // 导出迷雾格子数
            WorldMapFogData fogData = ScriptableObject.CreateInstance<WorldMapFogData>(); // 客户端用迷雾数据
            fogData.mapWidth = MapFogOutSize;
            fogData.mapHeight = MapFogOutSize;
            fogData.fogSize = MapFogSize;
            fogData.mapFogRunDtas = new List<MapFogRunDta>();

            List<MapAreaInfo> list = new List<MapAreaInfo>();
            var mapAreaInfo = mapAreaInfos[mapAreaEditorType.E_AREA];
            var mapResLevelInfo = mapAreaInfos[mapAreaEditorType.E_RESLEVEL];
            var mapCityInfo = mapAreaInfos[mapAreaEditorType.E_CITY];
            var mapMonsterInfo = mapAreaInfos[mapAreaEditorType.E_MONSTER];
            var maFogInfo = mapAreaInfos[mapAreaEditorType.E_FOGID];
            var maSmuggleInfo = mapAreaInfos[mapAreaEditorType.E_Monster_Smuggle_Level];
            int fogDataNum = 0;
            for (int i = 0; i < _generalMap.wSize * _generalMap.wSize; i++)
            {
                int idx_x = i % _generalMap.wSize;
                int idx_y = i / _generalMap.wSize;
                if (idx_x >= _generalMap.wSize || idx_y >= _generalMap.wSize) continue;
                MapAreaInfo info = new MapAreaInfo();
                info.index = i;

                int resLevel = 0;
                mapResLevelInfo.TryGetValue(i, out resLevel);
                info.resLevel = Mathf.Max(resLevel,0);

                int monsterLevel = 0;
                mapMonsterInfo.TryGetValue(i, out monsterLevel);
                info.monsterLevel = Mathf.Max(monsterLevel, 0);
     
                int cityLevel = 0;
                mapCityInfo.TryGetValue(i, out cityLevel);
                info.cityLevel = Mathf.Max(cityLevel, 0);
               
                int mapAreaId = 0;
                mapAreaInfo.TryGetValue(i, out mapAreaId);
                info.mapAreaId = Mathf.Max(mapAreaId, 0);

                int smuggleLevel = 0;
                maSmuggleInfo.TryGetValue(i, out smuggleLevel);
                info.smuggleLevel = Mathf.Max(smuggleLevel, 0);

                int fogId = 0;
                maFogInfo.TryGetValue(i, out fogId);
                info.fogId = Mathf.Max(fogId, 0);

                // 客户端迷雾数据 
                if (fogId > 0)
                {
                    MapFogRunDta fog = new MapFogRunDta();
                    fog.exploreId = fogId;
                    fog.indexMap_x = i % _generalMap.wSize;
                    fog.indexMap_y = i / _generalMap.wSize;
                    Vector2Int fogPos = GetFogPos(fog.indexMap_x, fog.indexMap_y);
                    fog.indexFog_x = fogPos.x;
                    fog.indexFog_y = fogPos.y;
                    fog.indexFog = fog.indexFog_x + fog.indexFog_y * MapFofLineNum;
                    fogData.AddFogData(fog);
                    // 记录迷雾数量
                    if (debugFogNum.TryGetValue(fogId, out int num))
                    {
                        debugFogNum[fogId] = num + 1;
                    }
                    else
                    {
                        debugFogNum[fogId] = 1;
                    }
                }
                else
                {
                    fogDataNum--;
                }

                list.Add(info);
            }
            AreaData ad = new AreaData();
            ad.mapSize = _generalMap.tileWidth * _generalMap.wSize;
            ad.mapAreaSize = _generalMap.tileWidth;
            ad.mapInfos = list.ToArray();

            // 新增海外区域数据
            if (_worldAllMap)
            {
                List<MapOverSeaInfo> overSeaInfos = new List<MapOverSeaInfo>();
                Dictionary<string, List<int>> overSeaIdxMap = new Dictionary<string, List<int>>();

                for (int i = 0; i < _worldAllMap.mapLODDatas[0].mapOverSeaChuncks.Count; i++)
                {
                    OverSeaChunck chunck = _worldAllMap.mapLODDatas[0].mapOverSeaChuncks[i];
                    if (chunck.info != null && chunck.info.overSeaType > 0 && chunck.info.overSeaUid > 0)
                    {
                        string key = chunck.info.overSeaType + "_" + chunck.info.overSeaUid;
                        int areaScale = WorldEntry.m_iTileSize / 10;
                        int lineNum = (WorldEntry.m_mapSize + WorldEntry.m_overSeaSize) / 10;

                        // 一个地图块需要导出 areaScale x areaScale个区域
                        for (int ii_x = 0; ii_x < areaScale; ii_x++)
                        {
                            for (int ii_y = 0; ii_y < areaScale; ii_y++)
                            {
                                int tile_x = chunck.offset_x * areaScale + ii_x;
                                int tile_y = chunck.offset_y * areaScale + ii_y;
                                int overSeaIdx = tile_x + tile_y * lineNum;

                                if (overSeaIdxMap.TryGetValue(key, out List<int> idxs))
                                {
                                    idxs.Add(overSeaIdx);
                                }
                                else
                                {
                                    List<int> idxs2 = new List<int>();
                                    idxs2.Add(overSeaIdx);
                                    overSeaIdxMap[key] = idxs2;
                                }
                            }
                        }
                    }
                }

                foreach (string overSeaKey in overSeaIdxMap.Keys)
                {
                    string[] keys = overSeaKey.Split("_");
                    int.TryParse(keys[0], out int overSeaType);
                    int.TryParse(keys[1], out int overSeaUid);
                    MapOverSeaInfo info = new MapOverSeaInfo();
                    info.type = overSeaType;
                    info.uid = overSeaUid;
                    info.index = overSeaIdxMap[overSeaKey].ToArray();
                    overSeaInfos.Add(info);
                }

                ad.overSeaInfos = overSeaInfos.ToArray();
            }
            else
            {
                ShowNotification(new GUIContent("导出区域数据需要设置地图存储数据"));
            }

            var ms = new MemoryStream();
            new DataContractJsonSerializer(ad.GetType()).WriteObject(ms, ad);
            var json = Encoding.UTF8.GetString(ms.ToArray());

            string path = Application.dataPath + "/ResourcesAssets/World/mapdata/";
            string filePath = path + "mapAreaData.json";
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }

            StreamWriter streamWriter = new StreamWriter(filePath);

            streamWriter.Write(json.ToString());
            streamWriter.Flush();
            streamWriter.Close();
            AssetDatabase.Refresh();

            fogDataNum += WorldEntry.m_mapSize * WorldEntry.m_mapSize;
            // 边界外迷雾
            foreach (int idx in mapFogInfos.Keys)
            {
                MapFogRunDta fog = mapFogInfos[idx];
                fogData.AddFogData(fog);
                fogDataNum++;
                // 记录迷雾数量
                if (debugFogNum.TryGetValue(fog.exploreId, out int num))
                {
                    debugFogNum[fog.exploreId] = num + 1;
                }
                else
                {
                    debugFogNum[fog.exploreId] = 1;
                }
            }
            AssetDatabase.CreateAsset(fogData, savePath + "mapFogData.asset");
            if (fogDataNum == MapFogOutSize * MapFogOutSize)
            { 
              
            }
            else
            {
                //Debug.LogError("导出迷雾数据数量不正确：" + fogDataNum);
            }

            DebugFogLine(fogData);
            DebugFogNum(debugFogNum);
            Debug.Log("导出地图区域数据成功：" + filePath);
        }
        // 导出迷雾虚线预制体
        void ExportFogLine(Dictionary<int, int> fogInfoMap)
        {
            GameObject fogLineRoot = new GameObject("FogLine");
            string path = "Assets/ResourcesAssets/World/prefabs/sandtable/fog/fogLine.prefab";
            GameObject fogline = (GameObject)AssetDatabase.LoadAssetAtPath<GameObject>(path);
            // 1、查找每个10x10的边界 分别记录在竖线 和 横线Map映射中 统一遵循 下到上 左到右的方向添加
            point_vertical.Clear();
            point_horizontal.Clear();
            mapEdgeLines.Clear();
            int MapFofLineNum1 = MapFofLineNum + 1;// 因为边界上的点也要添加
            for (int x = 0; x < MapFofLineNum; x++)
            {
                for (int y = 0; y < MapFofLineNum; y++)
                {
                    int idx = x + y * MapFofLineNum;
                    int idx1 = x + (y + 1) * MapFofLineNum1; // 上左
                    int idx2 = x + 1 + (y + 1) * MapFofLineNum1; // 上右
                    int idx3 = x + y * MapFofLineNum1; // 下左
                    int idx4 = x + 1 + y * MapFofLineNum1; // 下右
                    int fogId = fogInfoMap[idx];
                    // 上边界
                    if (!checkSameFog(x, y + 1, fogId,fogInfoMap))
                    {
                        // 添加到横线
                        point_horizontal[idx1] = idx2;
                    }
                    // 下边界
                    if (!checkSameFog(x, y - 1, fogId, fogInfoMap))
                    {
                        // 添加到横线
                        point_horizontal[idx3] = idx4;
                    }
                    // 左边界
                    if (!checkSameFog(x - 1, y, fogId, fogInfoMap))
                    {
                        // 添加到竖线
                        point_vertical[idx3] = idx1;
                    }
                    // 右边界
                    if (!checkSameFog(x + 1, y, fogId, fogInfoMap))
                    {
                        // 添加到竖线
                        point_vertical[idx4] = idx2;
                    }
                }
            }
            // 2、连接所有垂直线
            while (FindMinIdx(point_vertical,out int minIdx))
            {
                List<Vector3> points = new List<Vector3>();
                mapEdgeLines.Add(points);
                FindFogLine(minIdx,ref point_vertical);
            }
            // 3、连接所有水平线
            while (FindMinIdx(point_horizontal, out int minIdx))
            {
                List<Vector3> points = new List<Vector3>();
                mapEdgeLines.Add(points);
                FindFogLine(minIdx,ref point_horizontal);
            }
            // 4、实例化所有线段
            for (int i = 0; i < mapEdgeLines.Count; i++)
            {
                List<Vector3> points = mapEdgeLines[i];
                if (points.Count < 2) continue;
                GameObject foglineOne = GameObject.Instantiate(fogline, fogLineRoot.transform);
                foglineOne.name = "fogline";
                LineRenderer lineComp = foglineOne.GetComponent<LineRenderer>();
                lineComp.positionCount = 2;
                lineComp.startWidth = 0.1f;
                lineComp.endWidth = 0.1f;
                lineComp.SetPosition(0, points[0]);
                lineComp.SetPosition(1, points[1]);
            }
        }

        void FindFogLine(int idx,ref Dictionary<int,int> points)
        {
            List<Vector3> linePoints = mapEdgeLines[mapEdgeLines.Count - 1];
            int MapFofLineNum1 = MapFofLineNum + 1;// 因为边界上的点也要添加
            int x = idx % MapFofLineNum1;
            int y = Mathf.CeilToInt(idx / MapFofLineNum1);
            Vector2 vec2 = GetMapPosByFogPoint(x, y);
          
            if (points.ContainsKey(idx))
            {
                // 添加起点
                if (linePoints.Count == 0)
                {
                    linePoints.Add(new Vector3(vec2.x, 0.1f, vec2.y));
                }
                int idx1 = points[idx];
                points.Remove(idx);
                FindFogLine(idx1, ref points);
            }
            else
            {
                // 添加终点
                linePoints.Add(new Vector3(vec2.x, 0.1f, vec2.y));
            }
        }

        bool FindMinIdx(Dictionary<int,int> points, out int idx)
        {
            bool isFind = false;
            idx = MapFofLineNum * MapFofLineNum + 1;
            if (points.Keys.Count > 0)
            {
                foreach (int idx0 in points.Keys)
                {
                    if (idx0 < idx)
                    {
                        idx = idx0;
                        isFind = true;
                    }
                }
            }
            return isFind;
        }

        bool checkSameFog(int fog_x,int fog_y, int fogId, Dictionary<int, int> fogInfoMap)
        {
            bool isSame = true;
            if (fog_x < 0 || fog_y < 0 || fog_x >= MapFofLineNum || fog_y >= MapFofLineNum)
            {
                return isSame;
            }
            int idx = fog_x + fog_y * MapFofLineNum;
             isSame = fogInfoMap[idx] == fogId;
            return isSame;
        }

        // 导出迷雾相连
        void DebugFogLine(WorldMapFogData fogData)
        {
            Dictionary<int, List<int>> fogLines = new Dictionary<int, List<int>>();
            Dictionary<int, int> fogInfoMap = new Dictionary<int, int>();
            for (int i = 0; i < fogData.mapFogRunDtas.Count; i++)
            {
                MapFogRunDta fog = fogData.mapFogRunDtas[i];
                if (fog.exploreId > 0)
                {
                    fogInfoMap[fog.indexFog] = fog.exploreId;
                }
            }
            ExportFogLine(fogInfoMap);
            for (int x = 0; x < MapFofLineNum; x++)
            {
                for (int y = 0; y < MapFofLineNum; y++)
                {
                    int idx = x + y * MapFofLineNum;
                    if (fogInfoMap.ContainsKey(idx))
                    {
                        int exploreId = fogInfoMap[idx];
                        if (!fogLines.ContainsKey(exploreId))
                        {
                            fogLines[exploreId] = new List<int>();
                        }
                        // 检查上下左右
                        for (int x_idx = x - 1; x_idx <= x + 1; x_idx++)
                        {
                            for (int y_idx = x - 1; y_idx <= x + 1; y_idx++)
                            {
                                if (CheckInFogSize(x_idx, y_idx))
                                {
                                    int idx_1 = x_idx + y_idx * MapFofLineNum;
                                    if (fogInfoMap.ContainsKey(idx_1))
                                    {
                                        int exploreId_1 = fogInfoMap[idx_1];
                                        if (exploreId_1 != exploreId && !fogLines[exploreId].Contains(exploreId_1))
                                        {
                                            fogLines[exploreId].Add(exploreId_1);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            // 打印所有迷雾相连信息
            foreach (int exploreId in fogLines.Keys)
            {
                List<int> lineIds = fogLines[exploreId];
                if (lineIds.Count > 0)
                {
                    string strLineIds = "";
                    for (int i = 0; i < lineIds.Count; i++)
                    {
                        int lineId = lineIds[i];
                        if (i == lineIds.Count - 1)
                        {
                            strLineIds += lineId.ToString();
                        }
                        else
                        {
                            strLineIds += string.Format("{0};",lineId);
                        }
                  
                    }
                    Debug.LogWarningFormat("[迷雾相连数据] exploreId : {0} - {1}", exploreId, strLineIds);
                }
                else
                {
                    Debug.LogWarningFormat("[迷雾相连数据] exploreId : {0} - 没有相连的迷雾 请检查", exploreId);
                }
            }
        }

        // 导出迷雾数量
        void DebugFogNum(Dictionary<int, int> debugFogNum)
        {
            foreach (int exploreId in debugFogNum.Keys)
            {
                int num = debugFogNum[exploreId];
                Debug.LogWarningFormat("[迷雾数量] exploreId : {0} - {1}", exploreId, num);
            }
        }

        bool CheckInFogSize(int x, int y)
        {
            bool res = true;
            res = x >= 0 && x < MapFogOutSize;
            res = res && y >= 0 && y < MapFogOutSize;
            return res;
        }

        // 此处裁切 只能将区域外的迷雾数据删除 -还修改地图尺寸就嘎了策划
        void CropWorldMapAreaData()
        {
            List<MapAreaInfo> list = new List<MapAreaInfo>();
            var mapAreaInfo = mapAreaInfos[mapAreaEditorType.E_AREA];
            var mapResLevelInfo = mapAreaInfos[mapAreaEditorType.E_RESLEVEL];
            var mapCityInfo = mapAreaInfos[mapAreaEditorType.E_CITY];
            var mapMonsterInfo = mapAreaInfos[mapAreaEditorType.E_MONSTER];
            var mapFogInfo = mapAreaInfos[mapAreaEditorType.E_FOGID];

            int X_L = (int)cropVec4.x * 3;
            int X_R = (int)cropVec4.y * 3;
            int Y_B = (int)cropVec4.z * 3;
            int Y_T = (int)cropVec4.w * 3;
            int oldLineNum = _worldMap.mapWidth / 10;
            for (int i = 0; i < oldLineNum * oldLineNum; i++)
            {
                MapAreaInfo info = new MapAreaInfo();

                int resLevel = 0;
                mapResLevelInfo.TryGetValue(i, out resLevel);
                info.resLevel = Mathf.Max(resLevel, 0);

                int monsterLevel = 0;
                mapMonsterInfo.TryGetValue(i, out monsterLevel);
                info.monsterLevel = Mathf.Max(monsterLevel, 0);

                int cityLevel = 0;
                mapCityInfo.TryGetValue(i, out cityLevel);
                info.cityLevel = Mathf.Max(cityLevel, 0);

                int mapAreaId = 0;
                mapAreaInfo.TryGetValue(i, out mapAreaId);
                info.mapAreaId = Mathf.Max(mapAreaId, 0);

                int fogId = 0;
                mapFogInfo.TryGetValue(i, out fogId);
                info.fogId = Mathf.Max(fogId, 0);

                int x = i % oldLineNum;
                int y = i / oldLineNum;
                // 判断改坐标在裁切范围内
                bool dataX = (x + 1) > X_L && x < (oldLineNum - X_R);
                bool dataY = (y + 1) > Y_B && y < (oldLineNum - Y_T);
                if (dataX && dataY)
                {
                    info.index = list.Count;
                    list.Add(info);
                }
            }
            AreaData ad = new AreaData();
            ad.mapSize = (oldLineNum - X_L - X_R) * 10;
            ad.mapAreaSize = _generalMap.tileWidth;
            ad.mapInfos = list.ToArray();
            var ms = new MemoryStream();
            new DataContractJsonSerializer(ad.GetType()).WriteObject(ms, ad);
            var json = Encoding.UTF8.GetString(ms.ToArray());

            string path = Application.dataPath + "/ResourcesAssets/World/mapdata/";
            string filePath = path + "mapAreaData.json";
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }

            StreamWriter streamWriter = new StreamWriter(filePath);

            streamWriter.Write(json.ToString());
            streamWriter.Flush();
            streamWriter.Close();

            AssetDatabase.Refresh();

            Debug.Log("裁切地图区域数据成功：" + filePath);
        }

        void readMapAreaJson(string path)
        {
            path = GetPath(path);
            TextAsset content = AssetDatabase.LoadAssetAtPath<TextAsset>(path);
            if (content != null && content.text != null && content.text.Length > 0)
            {
                var mStream = new MemoryStream(Encoding.Default.GetBytes(content.text.ToCharArray()));
                var serializer = new DataContractJsonSerializer(typeof(AreaData));
                AreaData readConfig = (AreaData)serializer.ReadObject(mStream);

                if (mapAreaInfos == null)
                {
                    mapAreaInfos[mapAreaEditorType.E_RESLEVEL] = new Dictionary<int, int>();
                    mapAreaInfos[mapAreaEditorType.E_AREA] = new Dictionary<int, int>();
                    mapAreaInfos[mapAreaEditorType.E_CITY] = new Dictionary<int, int>();
                    mapAreaInfos[mapAreaEditorType.E_MONSTER] = new Dictionary<int, int>();
                    mapAreaInfos[mapAreaEditorType.E_FOGID] = new Dictionary<int, int>();
                    mapAreaInfos[mapAreaEditorType.E_Monster_Smuggle_Level] = new Dictionary<int, int>();
                }
       
                _generalMap.wSize = WorldEntry.m_mapSize / readConfig.mapAreaSize;
                _generalMap.hSize = WorldEntry.m_mapSize / readConfig.mapAreaSize;
                _generalMap.tileHeight = readConfig.mapAreaSize;
                _generalMap.tileWidth = readConfig.mapAreaSize;
                for (int i = 0;i < readConfig.mapInfos.Length;i++)
                {
                    MapAreaInfo mapAreaInfo = readConfig.mapInfos[i];
                    int idx = mapAreaInfo.index;
                    // 这里判断一下数据正确性 再赋值
                    if (CheckMapAreaData(mapAreaInfos[mapAreaEditorType.E_RESLEVEL],idx, mapAreaInfo.resLevel)) mapAreaInfos[mapAreaEditorType.E_RESLEVEL][idx] = mapAreaInfo.resLevel;
                    if (CheckMapAreaData(mapAreaInfos[mapAreaEditorType.E_AREA], idx, mapAreaInfo.resLevel)) mapAreaInfos[mapAreaEditorType.E_AREA][idx] = mapAreaInfo.mapAreaId;
                    if (CheckMapAreaData(mapAreaInfos[mapAreaEditorType.E_CITY], idx, mapAreaInfo.cityLevel)) mapAreaInfos[mapAreaEditorType.E_CITY][idx] = mapAreaInfo.cityLevel;
                    if (CheckMapAreaData(mapAreaInfos[mapAreaEditorType.E_MONSTER], idx, mapAreaInfo.resLevel)) mapAreaInfos[mapAreaEditorType.E_MONSTER][idx] = mapAreaInfo.monsterLevel;
                    if (mapAreaInfo.fogId != null)
                    {
                        if (CheckMapAreaData(mapAreaInfos[mapAreaEditorType.E_FOGID], idx, mapAreaInfo.resLevel)) mapAreaInfos[mapAreaEditorType.E_FOGID][idx] = mapAreaInfo.fogId;
                    }
                    else
                    {
                        mapAreaInfos[mapAreaEditorType.E_FOGID][idx] = 0;
                    }
                    if (mapAreaInfo.smuggleLevel != null)
                    {
                        if (CheckMapAreaData(mapAreaInfos[mapAreaEditorType.E_Monster_Smuggle_Level], 
                            idx, mapAreaInfo.smuggleLevel)) mapAreaInfos[mapAreaEditorType.E_Monster_Smuggle_Level][idx] = mapAreaInfo.smuggleLevel;
                    }
                    else
                    {
                        mapAreaInfos[mapAreaEditorType.E_Monster_Smuggle_Level][idx] = 0;
                    }
                }

                ShowNotification(new GUIContent("导入地图区域信息成功"));
            }

            // 读取地图迷雾数据 填充界外数据
            mapFogInfos = new Dictionary<int, MapFogRunDta>();
            string mapFogDataPath = savePath + "mapFogData.asset";
            WorldMapFogData fogData = AssetDatabase.LoadAssetAtPath<WorldMapFogData>(mapFogDataPath);
            if (fogData)
            {
                int fogWorldSize = WorldEntry.m_mapLandSize / 10;
                for (int i = 0; i < fogData.mapFogRunDtas.Count; i++)
                {
                    MapFogRunDta data = fogData.mapFogRunDtas[i];
                    if (data.indexMap_x < 0 || data.indexMap_y < 0 || data.indexMap_x >= fogWorldSize || data.indexMap_y >= fogWorldSize)
                    { 
                        mapFogInfos[data.indexFog] = data;
                    }
                }
            }
        }

        bool CheckMapAreaData(Dictionary<int,int> dict,int key, int value)
        {
            bool res = true;
            if (dict.ContainsKey(key))
            {
                res = !(dict[key] > 0 && value <= 0);
            }
            return res;
        }

        void DrawMapAreaInfo()
        {
            if (bMapAreaEditor)
            {
                Color oldColor = Gizmos.color;

                foreach (mapAreaEditorType type in mapAreaInfoEditorState.Keys)
                {
                    bool state = mapAreaInfoEditorState[type];
                    if (state)
                    {
                        var mapAreaInfo = mapAreaInfos[type];
                        foreach (int idx in mapAreaInfo.Keys)
                        {
                            int level = mapAreaInfo[idx];
                            if (type == mapAreaEditorType.E_FOGID)
                            {
                                // 利用10x10块预制体代替Gizmos
                                if (level <= 0)
                                {
                                    // 退还可能存在的预制体
                                    if (MapFogEditorObjs.ContainsKey(idx))
                                    {
                                        removeFogEditorObj(idx);
                                    }
                                }
                                else
                                {
                                    // 新增可能存在的预制体
                                    if (!MapFogEditorObjs.ContainsKey(idx))
                                    {
                                        addFogEditorObj(idx, level);
                                    }
                                    else
                                    {
                                        // 刷新对应等级
                                        YText text = MapFogEditorYTexts[idx];
                                        text.text = level.ToString();
                                    }
                                }

                            }
                            else if (level > 0)
                            {
                                Gizmos.color = mapAreaInfoEditorColor[type][level - 1];
                                float x = idx % _generalMap.wSize;
                                x = (x + 0.5f) * _generalMap.tileWidth;
                                float y = idx / _generalMap.wSize;
                                y = (y + 0.5f) * _generalMap.tileHeight;
                                Vector3 pos = new Vector3(x, 0.1f * level, y);
                                Gizmos.DrawCube(pos, new Vector3(_generalMap.tileWidth, 0.01f, _generalMap.tileHeight));
                            }
                        }

                        // 绘制迷雾地图外数据
                        if (type == mapAreaEditorType.E_FOGID)
                        {
                            int fogWorldSize = WorldEntry.m_mapLandSize / 10;
                            foreach (int idx in mapFogInfos.Keys)
                            {
                                MapFogRunDta fogData = mapFogInfos[idx];
                                if (fogData.indexMap_x < 0 || fogData.indexMap_y < 0 || fogData.indexMap_x >= fogWorldSize || fogData.indexMap_y >= fogWorldSize)
                                {
                                    if (fogData.exploreId != 0)
                                    {
                                        // 新增可能存在的预制体
                                        if (!MapFogOutEditorObjs.ContainsKey(fogData.indexFog))
                                        {
                                            addFogOutEditorObj(fogData.indexFog, fogData.exploreId);
                                        }
                                        else
                                        {
                                            // 刷新对应等级
                                            YText text = MapFogOutEditorYTexts[idx];
                                            text.text = fogData.exploreId.ToString();
                                        }
                                    }
                                    else
                                    {
                                        // 退还可能存在的预制体
                                        if (MapFogOutEditorObjs.ContainsKey(fogData.indexFog))
                                        {
                                            removeFogOutEditorObj(fogData.indexFog);
                                        }
                                    }
                                }
                            }
                        }
                    }
                
                }
                Gizmos.color = oldColor;
            }
        }

        //GameObject MapFogEditorRoot;
        //Dictionary<int, GameObject> MapFogEditorObjs = new Dictionary<int, GameObject>();
        //List<GameObject> MapFogEditorPool = new List<GameObject>();
        GameObject getFogEditorObj()
        {
            GameObject obj = null;
            if (MapFogEditorRoot == null)
            {
                MapFogEditorRoot = new GameObject();
                MapFogEditorRoot.name = "MapFogEditorRoot";
            }
            if (MapFogEditorPool.Count > 0)
            {
                obj = MapFogEditorPool[0];
                MapFogEditorPool.RemoveAt(0);
            }
            else
            {
                string path = "Assets/Arts/World/sandtable/prefabs/editor/sandtable_fog_editor.prefab";
                GameObject fogObj = (GameObject)AssetDatabase.LoadAssetAtPath<GameObject>(path);
                obj = GameObject.Instantiate(fogObj, MapFogEditorRoot.transform);
            }
            return obj;
        }

        void removeFogEditorObj(int idx)
        {
            GameObject obj = MapFogEditorObjs[idx];
            MapFogEditorPool.Add(obj);
            obj.SetActive(false);
            MapFogEditorObjs[idx] = null;
            MapFogEditorObjs.Remove(idx);
            MapFogEditorYTexts[idx] = null;
        }

        void addFogEditorObj(int idx,int level)
        {
            GameObject obj = getFogEditorObj();
            YText text = obj.GetComponentInChildren<YText>();
            if (text) {
                text.text = level.ToString();
            }
            float x = idx % _generalMap.wSize;
            x = (x + 0.5f) * _generalMap.tileWidth;
            float y = idx / _generalMap.wSize;
            y = (y + 0.5f) * _generalMap.tileHeight;
            Vector3 pos = new Vector3(x, 0.1f, y);
            obj.transform.position = pos;
            obj.SetActive(true);
            obj.name = level.ToString();
            MapFogEditorObjs[idx] = obj;
            MapFogEditorYTexts[idx] = text;
        }

        void removeFogOutEditorObj(int idx)
        {
            GameObject obj = MapFogOutEditorObjs[idx];
            if (obj == null)
            {
                int a = 0;
            }
            MapFogEditorPool.Add(obj);
            obj.SetActive(false);
            MapFogOutEditorObjs[idx] = null;
            MapFogOutEditorObjs.Remove(idx);
            MapFogOutEditorYTexts[idx] = null;
        }

        void addFogOutEditorObj(int idx, int level)
        {
            GameObject obj = getFogEditorObj();
            YText text = obj.GetComponentInChildren<YText>();
            if (text)
            {
                text.text = level.ToString();
            }
            MapFogRunDta fogData = mapFogInfos[idx];
            Vector3 pos = new Vector3((fogData.indexMap_x + 0.5f) * MapFogSize, 0.1f, (fogData.indexMap_y + 0.5f) * MapFogSize);
            obj.transform.position = pos;
            obj.SetActive(true);
            MapFogOutEditorObjs[idx] = obj;
            MapFogOutEditorYTexts[idx] = text;
        }

        void DisPoseFogEditor()
        {
            if (MapFogEditorRoot)
            {
                GameObject.DestroyImmediate(MapFogEditorRoot);
                MapFogEditorRoot = null;
            }
            MapFogEditorObjs.Clear();
            MapFogEditorYTexts.Clear();
            MapFogOutEditorObjs.Clear();
            MapFogOutEditorYTexts.Clear();
            MapFogEditorPool.Clear();
        }

        #endregion 

        #endregion

        #region 地图块相关函数

        private void CreateMapChunck()
        {
            if (mapChunckRoot == null)
            {
                ShowNotification(new GUIContent("请先设置地图块初始预制体"));
                return;
            }
            string name = mapChunckRoot.name;
            mapChunckRoot = Instantiate(mapChunckRoot);
            mapChunckRoot.name = name;
            mapChunckRoot.transform.localPosition = Vector3.zero;
            if (mapPlaneRoot == null)
            {
                mapPlaneRoot = new GameObject();
                mapPlaneRoot.gameObject.name = "放置打点对象根节点";
                mapPlaneRoot.transform.SetParent(mapChunckRoot.transform);
            }
        }

        private void CreateMapElement(Vector3 localPos, int type)
        {
            if (mapPlaneRoot == null)
            {
                ShowNotification(new GUIContent("请先设置地图块初始预制体"));
                return;
            }
            string modelStr = panelModel1Path;
            GameObject model = AssetDatabase.LoadAssetAtPath<GameObject>(modelStr);
            GameObject element;
            mapPointInfo info = new mapPointInfo();
            info.type = type;
            if (mapElement)
            {
                element = Instantiate(mapElement);
                GameObject plane = Instantiate(model);
                plane.name = "打点预制体";
                plane.SetActive(true);
                plane.transform.localScale = new Vector3(mapElementSize, mapElementSize, mapElementSize);
                plane.transform.parent = element.transform;
                plane.transform.localPosition = Vector3.zero;
                plane.layer = LayerMask.NameToLayer("MapPoint");
                Material mat = plane.GetComponent<MeshRenderer>().material;
                mat.color = typeToColorMap[type];
                pointTypeMap[plane] = mat;
                pointInfoMap[plane] = info;
            }
            else
            {
                element = Instantiate(model);
                element.SetActive(true);
                element.layer = LayerMask.NameToLayer("MapPoint");
                Material mat = element.GetComponent<MeshRenderer>().material;
                mat.color = typeToColorMap[type];
                pointTypeMap[element] = mat;
                pointInfoMap[element] = info;
            }
            element.transform.parent = mapPlaneRoot.transform;
            element.transform.localPosition = localPos;
            element.transform.localScale = Vector3.one * typeToSizeMap[type];
            element.gameObject.name = type.ToString();
        }

        void MarkAllPoint()
        {
            pointInfos.Clear();
            pointInfoMap.Clear();
            int localId = 0;
            // 首先检查一下有没有重叠的点
            Dictionary<int, GameObject> posCheck = new Dictionary<int, GameObject>();
            for (int i = 0; i < mapPlaneRoot.transform.childCount; i++)
            {
                Transform tfPoint = mapPlaneRoot.transform.GetChild(i);
                int cfgIdx = (int)(tfPoint.position.x + WorldEntry.m_iTileSize * 0.5f) + (int)(tfPoint.position.z + WorldEntry.m_iTileSize * 0.5f) * WorldEntry.m_iTileSize;
   
                if (posCheck.ContainsKey(cfgIdx))
                {
                    Debug.Log("[出生点] 出生点重复 1 =============== ", tfPoint.gameObject);
                    Debug.Log("[出生点] 出生点重复 2 =============== ", posCheck[cfgIdx]);
                    ShowNotification(new GUIContent("注意!导出的点数据有重复！"));
                }
                else
                {
                    posCheck[cfgIdx] = tfPoint.gameObject;
                }
            }

            for (int i = 0; i < mapPlaneRoot.transform.childCount; i++)
            {
                Transform tfPoint = mapPlaneRoot.transform.GetChild(i);
                mapPointInfo info = new mapPointInfo();
                info.localId = localId;
                info.localPos = new Vector2(tfPoint.position.x, tfPoint.position.z);
                GameObject plane = tfPoint.gameObject;
                if (plane.transform.childCount > 0)
                {
                    for (int ii = 0;ii< plane.transform.childCount;ii++)
                    {
                        if (plane.transform.GetChild(ii).gameObject.name == "打点预制体")
                        {
                            plane = plane.transform.GetChild(ii).gameObject;
                        }
                    }
                }

                //Material mat = plane.GetComponent<MeshRenderer>().material;
                int.TryParse(plane.gameObject.name, out info.type);
                localId++;
                // 判断该点不是在边界上 如果是在边界上 需要移动 0.01
                //{
                //    if (info.localPos.x == Math.Floor(info.localPos.x)) info.localPos.x -= 0.01f;
                //    if (info.localPos.y == Math.Floor(info.localPos.y)) info.localPos.y -= 0.01f;
                //}
                if (info.type == (int)WorldEntry.MapPointType.E_EditorResPoint)
                {
                    // 判断编辑用资源点是否在1x1的格子中心
                    float maxOffset = 0.5f - WorldEntry.resPointOffset;
                    float center_x = (tfPoint.position.x > 0) ? ((int)tfPoint.position.x + 0.5f) : ((int)tfPoint.position.x - 0.5f);
                    float center_y = (tfPoint.position.z > 0) ? ((int)tfPoint.position.z + 0.5f) : ((int)tfPoint.position.z - 0.5f);
                    bool bCenterX = MathF.Abs(tfPoint.position.x - center_x) < maxOffset;
                    bool bCenterY = MathF.Abs(tfPoint.position.z - center_y) < maxOffset;
                    if (!(bCenterX && bCenterY))
                    {
                        Debug.Log("[出生点] 出生点不在格子中心 =============== ", tfPoint.gameObject);
                        ShowNotification(new GUIContent("导出失败 注意!导出的辑用资源点不在格子中心！"));
                        return;
                    }
                }
               
                pointInfos.Add(info);
                pointInfoMap[tfPoint.gameObject] = info;
            }
        }

        //int GetTypeByColor(Color c)
        //{
        //    int type = 0;
        //    if (typeToColorMap.ContainsValue(c))
        //    {
        //        var keys = typeToColorMap.Where(q => q.Value == c).Select(q => q.Key);
        //        type = keys.ToList()[0];
        //    }
        //    return type;
        //}

        void SetPointType(GameObject obj, int type)
        {
            //if (type == (int)WorldEntry.MapPointType.E_EditorResPoint)
            //{
            //    // 判断编辑用资源点是否在1x1的格子中心
            //    float maxOffset = 0.5f - WorldEntry.resPointOffset;
            //    Vector3 pos = obj.transform.position;
            //    float center_x = (pos.x > 0) ? ((int)pos.x + 0.5f) : ((int)pos.x - 0.5f);
            //    float center_y = (pos.z > 0) ? ((int)pos.z + 0.5f) : ((int)pos.z - 0.5f);
            //    bool bCenterX = MathF.Abs(pos.x - center_x) < maxOffset;
            //    bool bCenterY = MathF.Abs(pos.z - center_y) < maxOffset;
            //    if (!(bCenterX && bCenterY))
            //    {
            //        Debug.Log("[出生点] 编辑的资源点位置不符合规范 =============== ", obj);
            //        ShowNotification(new GUIContent("编辑失败 注意!编辑的资源点位置不符合规范！"));
            //        return;
            //    }
            //}

            // 改变颜色
            GameObject plane = obj;
            if (obj.transform.childCount > 0)
            {
                plane = obj.transform.GetChild(0).gameObject;
            }
            if (pointInfoMap.ContainsKey(plane))
            {
                mapPointInfo info = pointInfoMap[plane];
                if (info.type != type)
                {
                    Material mat = pointTypeMap[plane];
                    if (mat) mat.color = typeToColorMap[type];
                    obj.transform.localScale = Vector3.one * typeToSizeMap[type];
                    obj.gameObject.name = type.ToString();
                }
            }
        }

        public static string StrReplace(string originalString, string strToBeReplaced, string strToReplace)
        {
            string resultString = null;
            char[] originalCharArray = originalString.ToCharArray();
            char[] strToBeCharArray = strToBeReplaced.ToCharArray();
            char[] strToCharArray = strToReplace.ToCharArray();
            List<Char> newCharList = new List<Char>();
            for (int i = 0; i < originalCharArray.Count(); i++)
            {
                if (originalCharArray[i] == strToBeCharArray[0])
                {
                    bool IsReplace = false;
                    for (int j = 0; j < strToBeCharArray.Count(); j++)
                    {
                        if (((i + j) < originalCharArray.Count())
                            && (originalCharArray[i + j] == strToBeCharArray[j]))
                        {
                            IsReplace = true;
                        }
                        else
                        {
                            IsReplace = false;
                            break;
                        }
                    }
                    if (IsReplace)
                    {
                        i += strToBeCharArray.Count() - 1;
                        for (int k = 0; k < strToCharArray.Count(); k++)
                        {
                            newCharList.Add(strToCharArray[k]);
                        }
                    }
                    else
                    {
                        newCharList.Add(originalCharArray[i]);
                    }
                }
                else
                {
                    newCharList.Add(originalCharArray[i]);
                }
            }

            resultString = string.Join("", newCharList);
            return resultString;
        }

        void ExportChunckPointData()
        {
            MarkAllPoint();
            chuckDataName = StrReplace(chuckDataName, "_Editor(Clone)", "");
            chuckDataName = StrReplace(chuckDataName, "_Editor", "");
            string filepath = savePointPath + chuckDataName + ".txt";

            if (!File.Exists(filepath))
            {
                File.Delete(filepath);
            }

            FileStream fs = new FileStream(filepath, FileMode.Create, FileAccess.Write);
            StreamWriter sw = new StreamWriter(fs, System.Text.Encoding.Default);
            string content = "";
            content += "id,x,y,type\n";
            content += "int32t,float,float,int32t\n";

            // 
            foreach (mapPointInfo point in pointInfos)
            {
                content += string.Format("{0},{1},{2},{3}\n",
                       point.localId, FixPos(point.localPos.x), FixPos(point.localPos.y), point.type);
            }

            if (string.IsNullOrEmpty(content) == false)
            {
                sw.Write(content);
            }

            sw.Close();
            fs.Close();
            if (pointSpecialCfgMap.Keys.Count > 0)
            {
                filepath = savePointPath + chuckDataName + "_special.txt";

                if (!File.Exists(filepath))
                {
                    File.Delete(filepath);
                }

                fs = new FileStream(filepath, FileMode.Create, FileAccess.Write);
                sw = new StreamWriter(fs, System.Text.Encoding.Default);
                content = "";
                content += "localId,cfgs\n";
                content += "int32t,string\n";

                // 
                foreach (GameObject obj in pointSpecialCfgMap.Keys)
                {
                    content += string.Format("{0},{1}\n",
                           obj.transform.GetSiblingIndex(), pointSpecialCfgMap[obj]);
                }

                if (string.IsNullOrEmpty(content) == false)
                {
                    sw.Write(content);
                }

                sw.Close();
                fs.Close();
          
            }
            AssetDatabase.Refresh();
        }
        private float FixPos(float value)
        {
            float value1 = float.Parse(string.Format("{0:f2}", value));
            return value1;
        }
        IEnumerator LoadChunckPointData()
        {
            DisposeChunckEditorRes();
            pointInfos = new List<mapPointInfo>();
            // 选择默认路径 打开
            string path = EditorUtility.OpenFilePanel("地图块数据导入", savePointPath, "txt");
            path = GetPath(path);

            if (!string.IsNullOrEmpty(path))
            {
                TextAsset content = AssetDatabase.LoadAssetAtPath<TextAsset>(path);
                if (content != null && content.text != null && content.text.Length > 0)
                {
                    var csvText = content.text.Trim();
                    var lines = csvText.Split(new char[1] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
                    //
                    chuckDataName = content.name;
                  
                    CreateMapChunck();
                    //
                    for (int i = 2; i < lines.Length; i++)
                    {
                        var l = lines[i];
                        var data = l.Split(',');

                        if (data.Length == 4)
                        {
                            float.TryParse(data[1], out float x);
                            float.TryParse(data[2], out float z);
                            int.TryParse(data[3], out int type);
                            CreateMapElement(new Vector3(x,0,z), type);
                            mapPointInfo info = new mapPointInfo();
                            info.type = type;
                            info.localPos.x = x;
                            info.localPos.y = z;
                            info.localId = i - 2;
                            pointInfos.Add(info);
                        }
                    }
                    ShowNotification(new GUIContent("地图块数据导入成功!"));
                }

                path = StrReplace(path, ".txt", "_special.txt");
                content = AssetDatabase.LoadAssetAtPath<TextAsset>(path);
                if (content != null && content.text != null && content.text.Length > 0)
                {
                    pointSpecialCfgMap.Clear();
                    var csvText = content.text.Trim();
                    var lines = csvText.Split(new char[1] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
                    //
                    for (int i = 2; i < lines.Length; i++)
                    {
                        var l = lines[i];
                        var data = l.Split(',');

                        if (data.Length == 2)
                        {
                            int.TryParse(data[0], out int locaId);
                            string cfgs = data[1];
                            Transform tf = mapPlaneRoot.transform.GetChild(locaId);
                            if (tf)
                            {
                                pointSpecialCfgMap[tf.gameObject] = cfgs;
                            }
                        }
                    }
                }
                yield return null;
            }
            else
            {
                ShowNotification(new GUIContent("地图块数据错误!请检查地图块数据路径正确"));
                Debug.LogError("地图块数据错误! " + path);
            }
        }

        string GetPath(string path)
        {
            string res = "";
            string[] paths = path.Split('/');
            int start_idx = 0;
            for (int i = 0; i < paths.Length; i++)
            {
                if (paths[i] == "Assets")
                {
                    start_idx = i;
                    res = "Assets/";
                }
                if (i > start_idx)
                {
                    if (i < paths.Length - 1)
                    {
                        res += (paths[i] + "/");
                    }
                    else
                    {
                        res += (paths[i]);
                    }
                }
            }
            return res;
        }

        void DisposeChunckEditorRes()
        {
            if (mapElement) DestroyImmediate(mapElement);
            if (mapPlaneRoot) DestroyImmediate(mapPlaneRoot);
            s_mapElementSize = "2";
            mapElementSize = 2;
            chuckDataName = "";
            bSetPlaneType = false;
            bSetPointCfg = false;
            pointSpecialCfg.Clear();
            UnityEditor.Tools.lockedLayers = 0;
            pointInfos.Clear();
            pointInfoMap.Clear();
            pointTypeMap.Clear();
            Resources.UnloadUnusedAssets();
            GameObject go = GameObject.Find("GizmosRoot");
            if (go != null) DestroyImmediate(go);
        }

        // ==================== 交通路点相关函数 ====================

        // 技术文档：https://youzu.feishu.cn/docs/doccn2kasrSoGhzi7k4BhH732Se#

        TrafficSystem trafficSystem;
        int trafficNodeIdx = 0;
        List<TrafficNode> trafficNodes = new List<TrafficNode>();

        GameObject trafficNodeModel;// 路点模型
        MapChunckTrafficData tempInportData;
        public struct TrafficTempLineInfo {
            public TrafficPoint start;
            public TrafficPoint end;
        }

        List<TrafficTempLineInfo> _curEditorTrafficLine = new List<TrafficTempLineInfo>();
        List<List<TrafficLineData>> _curTrafficLineDatas = new List<List<TrafficLineData>>();
        List<bool> _curTrafficLineShow = new List<bool>();
        private void OnGUIofToolTraffic()
        {
            DevelopmentToolsGFoldOut = FoldoutReset(DevelopmentToolsGFoldOut, "地图块交通信息相关");
            if (DevelopmentToolsGFoldOut)
            {
                mapChunckTrafficObj = (GameObject)EditorGUILayout.ObjectField("地图块节点", mapChunckTrafficObj, typeof(GameObject), true);
                GameObject trafficSystemObj = null;
                if (trafficSystem) trafficSystemObj = trafficSystem.gameObject;
                trafficSystemObj = (GameObject)EditorGUILayout.ObjectField("地图交通节点", trafficSystemObj, typeof(GameObject), true);
                if (trafficSystem == null && trafficSystemObj)
                {
                    trafficSystem = trafficSystemObj.GetComponent<TrafficSystem>();
                    // 重新绑定
                    trafficNodes.Clear();
                    _curEditorTrafficLine.Clear();
                    _curTrafficLineDatas.Clear();
                    _curTrafficLineShow.Clear();

                    for (int i = 0; i < trafficSystem.transform.childCount; i++)
                    {
                        Transform tf = trafficSystem.transform.GetChild(i);
                        TrafficNode tNode = tf.GetComponent<TrafficNode>();
                        if (tNode)
                        {
                            int nodeId = tNode.nodeId;
                            if (nodeId <= 0) nodeId = trafficNodeIdx;
                            tNode.Init(nodeId);
                            trafficNodeIdx = Mathf.Max(tNode.nodeId, trafficNodeIdx);
                            trafficNodes.Add(tNode);
                        }
                    }
                }
                if (GUILayout.Button("创建地图块交通系统"))
                {
                    CreateTrafficSystem();
                }
                GUILayout.BeginHorizontal();
                trafficNodeModel = (GameObject)EditorGUILayout.ObjectField("交通节点模板", trafficNodeModel, typeof(GameObject), true, GUILayout.Width(300));

                if (bEditorTrafficData)
                {
                    UnityEditor.Tools.lockedLayers = -1;
                    Selection.activeGameObject = null;
                }
                else
                {
                    UnityEditor.Tools.lockedLayers = 0;
                }

                if (GUILayout.Button("添加一个路点"))
                {
                    CreateTrafficNode();
                }
                GUILayout.EndHorizontal();
                GUILayout.BeginHorizontal();
                GUILayout.Label("编辑路线状态:", GUILayout.Width(70));
                bEditorTrafficData = EditorGUILayout.Toggle(bEditorTrafficData, GUILayout.Width(40));
                GUILayout.Label("勾选情况下按下找到起点，拖动到终点松开添加线段；S键将所有线段保存成路线,Delete键删除最后一条线段");
                GUILayout.EndHorizontal();
                if (_curTrafficLineDatas.Count > 0)
                {
                    GUILayout.BeginVertical();
                    GUILayout.Label("编辑路线数据:", GUILayout.Width(110));
                    GUILayout.BeginScrollView(new Vector2(600, 50), false, true, GUILayout.Height(25 * Mathf.Floor(_curTrafficLineDatas.Count / 3)));
                    for (int i = 0; i < _curTrafficLineDatas.Count;)
                    {
                        GUILayout.BeginHorizontal();
                        for (int ii = 0; ii < 3 && i < _curTrafficLineDatas.Count; ii++)
                        {
                            _curTrafficLineShow[i] = GUILayout.Toggle(_curTrafficLineShow[i], "", GUILayout.Width(20));
                            GUILayout.Label("路线" + i.ToString(), GUILayout.Width(40));
                            if (GUILayout.Button("删除", GUILayout.Width(40)))
                            {
                                _curTrafficLineDatas.RemoveAt(i);
                                _curTrafficLineShow.RemoveAt(i);
                            }
                            GUILayout.Space(20);
                            i++;
                        }
                        GUILayout.EndHorizontal();
                    }
                    GUILayout.EndScrollView();
                    GUILayout.EndVertical();
                }
              
                if (GUILayout.Button("导出地图块交通数据"))
                {
                    ExportMapChunckTraffic();
                }
                GUILayout.BeginHorizontal();
                tempInportData = (MapChunckTrafficData)EditorGUILayout.ObjectField("地图块路线数据", tempInportData, typeof(MapChunckTrafficData), true, GUILayout.Width(300));
                if (GUILayout.Button("导入交通路线") && tempInportData)
                {
                    //List<List<TrafficLineData>> _curTrafficLineDatas = new List<List<TrafficLineData>>();
                    _curTrafficLineDatas.Clear();
                    _curTrafficLineShow.Clear();
                    for (int i = 0; i < tempInportData.trafficLineDatas.Count;i++)
                    {
                        List<TrafficLineData> data = new List<TrafficLineData>();
                        for (int ii = 0; ii < tempInportData.trafficLineDatas[i].trafficLineDataOne.Count; ii++)
                        {
                            TrafficLineData oneData = tempInportData.trafficLineDatas[i].trafficLineDataOne[ii];
                            data.Add(oneData);
                        }
                        _curTrafficLineDatas.Add(data);
                        _curTrafficLineShow.Add(true);
                    }
                }
                GUILayout.EndHorizontal();
                GUI.enabled = true;
            }
        }

        // 创建交通系统根节点
        private void CreateTrafficSystem()
        {
            GameObject obj = new GameObject();
            obj.transform.localPosition = Vector3.zero;
            obj.name = "TrafficSystem";
            trafficSystem = obj.AddComponent<TrafficSystem>(); 
        }

        private void CreateTrafficNode()
        {
            if (trafficSystem)
            {
                GameObject obj;
                TrafficNode node;
                if (trafficNodeModel)
                {
                    obj = Instantiate(trafficNodeModel);
                }
                else
                {
                    obj = new GameObject();
                }
                obj.transform.localPosition = Vector3.zero;
                trafficNodeIdx++;
                obj.name = "Node_" + trafficNodeIdx;
                obj.transform.parent = trafficSystem.transform;
                node = obj.GetOrAddComponent<TrafficNode>();
                node.Init(trafficNodeIdx);
                trafficNodes.Add(node);
            }
        }

        private void AddMapChunckTrafficOne()
        {
            if (trafficDragObj != null && trafficDragEndObj != null)
            {
                TrafficTempLineInfo info = new TrafficTempLineInfo();
                info.start = trafficDragObj;
                info.end = trafficDragEndObj;
                Debug.Log("[交通] 点击路点 ================== 抬起 起点 : " + trafficDragObj.name + " 终点 : " + trafficDragEndObj.name);
                _curEditorTrafficLine.Add(info);
                trafficDragObj.drawScale = 1.0f;
                trafficDragObj = null;
                trafficDragEndObj.drawScale = 1.0f;
                trafficDragEndObj = null;
                Repaint();
            }
        }

        private void RemoveMapChunckTrafficOne()
        {
            if (_curEditorTrafficLine != null && _curEditorTrafficLine.Count > 0)
            {
                _curEditorTrafficLine.RemoveAt(_curEditorTrafficLine.Count - 1);
                Repaint();
            }
        }

        private void AddMapChunckTrafficLine()
        {
            if (_curEditorTrafficLine.Count <= 0) return;
            List<TrafficLineData> lineData = new List<TrafficLineData>();
            for (int i = 0; i < _curEditorTrafficLine.Count;i++)
            {
                TrafficLineData data = new TrafficLineData();
                data.pointId = _curEditorTrafficLine[i].start.pointId;
                data.nodeId = _curEditorTrafficLine[i].start.transform.parent.GetComponent<TrafficNode>().nodeId;
                lineData.Add(data);

                if (i == _curEditorTrafficLine.Count - 1)
                {
                    TrafficLineData endData = new TrafficLineData();
                    endData.pointId = _curEditorTrafficLine[i].end.pointId;
                    endData.nodeId = _curEditorTrafficLine[i].end.transform.parent.GetComponent<TrafficNode>().nodeId;
                    lineData.Add(endData);
                }
            }
            _curEditorTrafficLine.Clear();
            _curTrafficLineDatas.Add(lineData);
            _curTrafficLineShow.Add(true);
        }

        TrafficNode GetTrafficNode(int nodeId)
        {
            TrafficNode node = null;
            for (int i = 0; i < trafficNodes.Count; i++)
            {
                if (trafficNodes[i].nodeId == nodeId) node = trafficNodes[i];
            }
            return node;
        }

        // 导出地图交通数据
        private void ExportMapChunckTraffic()
        {
            var data = ScriptableObject.CreateInstance<MapChunckTrafficData>();
            data.trafficNodeDatas = new List<TrafficNodeData>();
            for (int i = 0; i < trafficNodes.Count; i++)
            {
                data.trafficNodeDatas.Add(trafficNodes[i].GetNodeData());
            }
            data.trafficLineDatas = new List<TrafficLineDataOne>();
            for (int i = 0; i < _curTrafficLineDatas.Count; i++)
            {
                TrafficLineDataOne dataOne = new TrafficLineDataOne();
                dataOne.trafficLineDataOne = new List<TrafficLineData>();
                dataOne.trafficLineDataOne = _curTrafficLineDatas[i];
                data.trafficLineDatas.Add(dataOne);
            }
            AssetDatabase.CreateAsset(data, savePath + mapChunckTrafficObj.name + "_trafficData.asset");
        }

        public static Vector3 GetMousePosToScene()
        {
            SceneView sceneView = SceneView.currentDrawingSceneView;
            //当前屏幕坐标,左上角(0,0)右下角(camera.pixelWidth,camera.pixelHeight)
            Vector2 mousePos = Event.current.mousePosition;
            //retina 屏幕需要拉伸值
            float mult = 1;
#if UNITY_5_4_OR_NEWER
            mult = EditorGUIUtility.pixelsPerPoint;
#endif
            //转换成摄像机可接受的屏幕坐标,左下角是(0,0,0);右上角是(camera.pixelWidth,camera.pixelHeight,0)
            mousePos.y = sceneView.camera.pixelHeight - mousePos.y * mult;
            mousePos.x *= mult;
            //近平面往里一些,才能看到摄像机里的位置
            Vector3 fakePoint = mousePos;
            fakePoint.z = 20;
            Vector3 point = sceneView.camera.ScreenToWorldPoint(fakePoint);
            return point;
        }

        void OnTrafficEditorEvent()
        {
            Event e = Event.current;
            // 地图块交通编辑
            if (bEditorTrafficData)
            {
                switch (e.type)
                {
                    case EventType.MouseDown:
                        if (trafficDragObj) break;
                        // 检测点击到坐标点

                        RaycastHit hit;
                        Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);

                        // hit.point 就是投射到地图上面的坐标 对应 x-z坐标系 到 x-y坐标系
                        RaycastHit[] hits = Physics.RaycastAll(ray);
                        for (int i = 0; i < hits.Length; i++)
                        {
                            RaycastHit res = hits[i];
                            TrafficPoint point = res.transform.GetComponent<TrafficPoint>();
                            if (point)
                            {
                                trafficDragObj = point; // 捕获起点
                                trafficDragObj.drawScale = 1.2f;
                                trafficDragEndObj = null;
                            }
                        }
                        break;
                    case EventType.MouseUp:
                        // 存在终点 抬起鼠标
                        if (trafficDragEndObj != null)
                        {
                            // 添加线段
                            AddMapChunckTrafficOne();
                        }
                        else
                        {
                            if (trafficDragObj) trafficDragObj.drawScale = 1.0f;
                            trafficDragObj = null;
                        }
                        break;
                    case EventType.MouseDrag:
                        // 编辑状态 + 存在拖拽起始点
                        if (trafficDragObj)
                        {
                            // 检测下一个点
                            RaycastHit hit2;
                            Ray ray2 = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);

                            RaycastHit[] hits2 = Physics.RaycastAll(ray2);
                            bool bFindPoint = false;
                            for (int i = 0; i < hits2.Length; i++)
                            {
                                RaycastHit res = hits2[i];
                                TrafficPoint point = res.transform.GetComponent<TrafficPoint>();
                                TrafficPoint lastEndDragObj = trafficDragEndObj;
                                if (point)
                                {
                                    if (point.gameObject != trafficDragObj.gameObject && point != trafficDragEndObj)
                                    {
                                        trafficDragEndObj = point;
                                        point.SetPointDrawSize(1.2f);
                                        if (lastEndDragObj)
                                        {
                                            lastEndDragObj.SetPointDrawSize(1.0f);
                                        }
                                    }
                                    bFindPoint = true;
                                }
                            }
                            if (bFindPoint == false)
                            {
                                if (trafficDragEndObj)
                                {
                                    TrafficPoint lastPoint = trafficDragEndObj.transform.GetComponent<TrafficPoint>();
                                    lastPoint.SetPointDrawSize(1.0f);
                                }
                            }
                        }
                        break;
                    case EventType.KeyDown:
                        switch (e.keyCode)
                        {
                            case KeyCode.S:
                                // 检测线段连接
                                // 显示勾选线段
                                // 保存当前所有线段
                                AddMapChunckTrafficLine();
                                break;
                            case KeyCode.Delete:
                                RemoveMapChunckTrafficOne();
                                break;
                        }
                        break;
                }

            }
        }

        void OnTrafficEditorEventEnd()
        {
            Event e = Event.current;
            // 地图块交通编辑
            if (bEditorTrafficData)
            {
                switch (e.type)
                {
                    case EventType.MouseDown:
                        if (trafficDragObj) break;
                        // 检测点击到坐标点

                        RaycastHit hit;
                        Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);

                        // hit.point 就是投射到地图上面的坐标 对应 x-z坐标系 到 x-y坐标系
                        RaycastHit[] hits = Physics.RaycastAll(ray);
                        for (int i = 0; i < hits.Length; i++)
                        {
                            RaycastHit res = hits[i];
                            TrafficPoint point = res.transform.GetComponent<TrafficPoint>();
                            if (point)
                            {
                                trafficDragObj = point; // 捕获起点
                                trafficDragObj.drawScale = 1.2f;
                                trafficDragEndObj = null;
                            }
                        }
                        break;
                    case EventType.MouseUp:
                        // 存在终点 抬起鼠标
                        if (trafficDragEndObj != null)
                        {
                            // 添加线段
                            AddMapChunckTrafficOne();
                        }
                        else
                        {
                            if(trafficDragObj) trafficDragObj.drawScale = 1.0f;
                            trafficDragObj = null;
                        }
                        break;
                    case EventType.MouseDrag:
                        // 编辑状态 + 存在拖拽起始点
                        if (trafficDragObj)
                        {
                            // 检测下一个点
                            RaycastHit hit2;
                            Ray ray2 = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);

                            RaycastHit[] hits2 = Physics.RaycastAll(ray2);
                            bool bFindPoint = false;
                            for (int i = 0; i < hits2.Length; i++)
                            {
                                RaycastHit res = hits2[i];
                                TrafficPoint point = res.transform.GetComponent<TrafficPoint>();
                                TrafficPoint lastEndDragObj = trafficDragEndObj;
                                if (point)
                                {
                                    if (point.gameObject != trafficDragObj.gameObject && point != trafficDragEndObj)
                                    {
                                        trafficDragEndObj = point;
                                        point.SetPointDrawSize(1.2f);
                                        if (lastEndDragObj)
                                        {
                                            lastEndDragObj.SetPointDrawSize(1.0f);
                                        }
                                    }
                                    bFindPoint = true;
                                }
                            }
                            if (bFindPoint == false)
                            {
                                if (trafficDragEndObj)
                                {
                                    TrafficPoint lastPoint = trafficDragEndObj.transform.GetComponent<TrafficPoint>();
                                    lastPoint.SetPointDrawSize(1.0f);
                                }
                            }
                        }
                        break;
                }

            }
        }

        // 性能分级 暂时不用 默认 关卡阻挡、地表0 其他1
        private void OnGUIofToolPerformance()
        {
            //DevelopmentToolsHFoldOut = FoldoutReset(DevelopmentToolsHFoldOut, "地图块性能分级相关");
            //if (DevelopmentToolsHFoldOut)
            //{
            //    EditorGUI.BeginChangeCheck();
            //    mapChunckLevelObj = (GameObject)EditorGUILayout.ObjectField("地图块节点", mapChunckLevelObj, typeof(GameObject), true);
            //    if (EditorGUI.EndChangeCheck())
            //    {
            //        ShowNotification(new GUIContent("注意!重新绑定地图块节点后之前的分级信息会被清除!"));
            //        ResetMapChunckLevelMap();
            //        bMapChunckDebug = false; // 性能分级调试开关
            //        MapChunckDebugLevel = 0;// 性能分级调试等级
            //    }
            //    // 性能调试开关
            //    EditorGUI.BeginChangeCheck();
            //    EditorGUILayout.BeginHorizontal();
            //    GUILayout.Label("性能分级调试:", GUILayout.Width(110));
            //    GUILayout.Space(40);
            //    bMapChunckDebug = EditorGUILayout.Toggle(bMapChunckDebug, GUILayout.Width(150));
            //    if (EditorGUI.EndChangeCheck())
            //    {
            //        // 刷新等级显示
            //        RefreshPerformance();
            //    }
            //    EditorGUILayout.EndHorizontal();
            //    // 性能调试等级
            //    EditorGUI.BeginChangeCheck();
            //    MapChunckDebugLevel = EditorGUILayout.IntField("性能分级调试等级 ", MapChunckDebugLevel);
            //    if (EditorGUI.EndChangeCheck())
            //    {
            //        // 刷新等级显示
            //        RefreshPerformance();
            //    }

            //    mapChunckLevelData = (WorldMapData)EditorGUILayout.ObjectField("地图块数据", mapChunckLevelData, typeof(WorldMapData), true);
            //    if (GUILayout.Button("导入地图块分级数据(注意！该数据要和当前地图块元素一致)"))
            //    {
            //        if(mapChunckLevelObj == null) ShowNotification(new GUIContent("注意!地图块节点为空!"));
            //        Transform tfTree = mapChunckLevelObj.transform.Find("LayerTree/LOD1");
            //        if (mapChunckLevelData != null) {
            //            for (int i = 0; i < mapChunckLevelData.mapLayers.Count;i++)
            //            {
            //                var layer = mapChunckLevelData.mapLayers[i];
            //                if (layer.layerID == WorldEntry.TREE_LAYER_ID)
            //                {
            //                    for (int ii = 0; ii < layer.mapLODDatas[0].chunckData.properties.Count; ii++)
            //                    {
            //                        var data = layer.mapLODDatas[0].chunckData.properties[ii];
            //                        Transform tf = tfTree.GetChild(ii);
            //                        MeshRenderer m = tf.GetComponent<MeshRenderer>();
            //                        if (m == null) m = tf.GetComponentInChildren<MeshRenderer>();
            //                        if (m)
            //                        {
            //                            Color c = mapChunckLevelColor[data.level];
            //                            MapChunckLevelMap[tf.gameObject] = data.level;
            //                            m.material.SetColor("_TintColor", c);
            //                            m.material.SetColor("_Tint", c);
            //                        }
            //                    }
            //                }
            //            }
            //        }
            //    }
            //}
        }

        private void ResetMapChunckLevelMap()
        {
            MapChunckLevelMap = new Dictionary<GameObject, int>();
            if (mapChunckLevelObj)
            {
                if(PrefabUtility.IsPartOfPrefabInstance(mapChunckLevelObj)) PrefabUtility.UnpackPrefabInstance(mapChunckLevelObj, PrefabUnpackMode.OutermostRoot, InteractionMode.UserAction);
                var meshs = mapChunckLevelObj.transform.GetComponentsInChildren<MeshRenderer>();
                int mapNum = 0;
                for (int i = 0; i < meshs.Length; i++)
                {
                    MeshRenderer mesh = meshs[i];
                    Transform parent = mesh.transform.parent;
                    if (mesh.transform.name.Contains("OBJ")) // 说明是地图块元素
                    {
                        MapChunckLevelMap[mesh.gameObject] = -1;
                        mesh.material.SetColor("_TintColor", Color.white);
                        mesh.material.SetColor("_Tint", Color.white);
                        continue;
                    }
                    if (parent && parent.name.Contains("OBJ")) // 说明是地图块元素
                    {
                        MapChunckLevelMap[parent.gameObject] = -1;
                        mesh.material.SetColor("_TintColor", Color.white);
                        mesh.material.SetColor("_Tint", Color.white);
                    }
                    else if(parent.parent && parent.parent.name.Contains("OBJ"))
                    {
                        MapChunckLevelMap[parent.parent.gameObject] = -1;
                        mesh.material.SetColor("_TintColor", Color.white);
                        mesh.material.SetColor("_Tint", Color.white);
                    }
                }
                foreach (GameObject obj in MapChunckLevelMap.Keys)
                {
                    mapNum++;
                }
                ShowNotification(new GUIContent("重新绑定地图块分级对象数量: " + mapNum));
            }
        }

        private void RefreshPerformance()
        {
            foreach (GameObject obj in MapChunckLevelMap.Keys)
            {
                int level = MapChunckLevelMap[obj];
                obj.SetActive((level <= MapChunckDebugLevel || bMapChunckDebug));
            }
        }

        #endregion 地图块相关函数

        #region 地图块装饰物相关函数

        private void CreatePointRoot()
        {
            if (_pointAdornChunck)
            {
                Transform tf = _pointAdornChunck.transform.Find("LayerPoint");
                if (tf) _pointRoot = tf.gameObject;
            }
            if (_pointRoot == null)
            {
                _pointRoot = new GameObject();
                _pointRoot.gameObject.name = "LayerPoint";
                _pointRoot.transform.SetParent(_pointAdornChunck.transform);
            }
        }

        string pointModel1Path = "Assets/Arts/World/sandtable/prefabs/pointElemnt.prefab";
        private GameObject CreatePointElement(Vector3 localPos, int type)
        {
            string modelStr = pointModel1Path;
            GameObject model = AssetDatabase.LoadAssetAtPath<GameObject>(modelStr);
            GameObject element;
            element = Instantiate(model);
            element.SetActive(true);
            element.layer = LayerMask.NameToLayer("MapPoint");
            SpriteRenderer sprite = element.GetComponent<SpriteRenderer>();
            sprite.color = typeToColorMap[type];
            element.transform.parent = _pointRoot.transform;
            element.transform.localPosition = localPos;
            element.transform.localScale = Vector3.one * 100;
            element.gameObject.name = type.ToString();
            return element;
        }

        IEnumerator LoadChunckPointData2()
        {
            // 选择默认路径 打开
            string path = EditorUtility.OpenFilePanel("地图块数据导入", savePointPath, "txt");
            path = GetPath(path);

            if (!string.IsNullOrEmpty(path))
            {
                TextAsset content = AssetDatabase.LoadAssetAtPath<TextAsset>(path);
                if (content != null && content.text != null && content.text.Length > 0)
                {
                    var csvText = content.text.Trim();
                    var lines = csvText.Split(new char[1] { '\n' }, StringSplitOptions.RemoveEmptyEntries);

                    CreatePointRoot();
                    //
                    for (int i = 2; i < lines.Length; i++)
                    {
                        var l = lines[i];
                        var data = l.Split(',');

                        if (data.Length == 4)
                        {
                            float.TryParse(data[1], out float x);
                            float.TryParse(data[2], out float z);
                            int.TryParse(data[3], out int type);
                            if (typeToPointEditor.ContainsKey(type))
                            { 
                                GameObject obj = CreatePointElement(new Vector3(x, 0, z), type);
                            }
                        }
                    }
                }
                yield return null;
            }
        }

        IEnumerator UpdateChunckPointData2()
        {
            // 选择默认路径 打开
            string path = EditorUtility.OpenFilePanel("地图块数据导入", savePointPath, "txt");
            path = GetPath(path);

            if (!string.IsNullOrEmpty(path))
            {
                TextAsset content = AssetDatabase.LoadAssetAtPath<TextAsset>(path);
                if (content != null && content.text != null && content.text.Length > 0)
                {
                    var csvText = content.text.Trim();
                    var lines = csvText.Split(new char[1] { '\n' }, StringSplitOptions.RemoveEmptyEntries);

                    CreatePointRoot();
                 
                    //
                    for (int i = 2; i < lines.Length; i++)
                    {
                        var l = lines[i];
                        var data = l.Split(',');

                        if (data.Length == 4)
                        {
                            float.TryParse(data[1], out float x);
                            float.TryParse(data[2], out float z);
                            int.TryParse(data[3], out int type);
                            // 找到LayerPointAdorn节点下对应坐标的点 刷新其大小 颜色...
                            
                            //element.layer = LayerMask.NameToLayer("MapPoint");
                            //SpriteRenderer sprite = element.GetComponent<SpriteRenderer>();
                            //sprite.color = typeToColorMap[type];
                            //element.transform.parent = _pointRoot.transform;
                            //element.transform.localPosition = localPos;
                            //element.transform.localScale = Vector3.one * 100;
                            //element.gameObject.name = type.ToString();
                        }
                    }
                    if (_pointAdornRootScript)
                    {
                        _pointAdornRootScript.FindAdorn();
                    }
                }
                yield return null;
            }
        }

        void LoadChunckPointData3()
        {
            CreatePointRoot();
            PointAdornModel[] models = _pointAdornRootScript.transform.GetComponentsInChildren<PointAdornModel>();
            for (int i = 0; i < models.Length; i++)
            {
                GameObject.DestroyImmediate(models[i].gameObject);
            }
            //
            string[] modelGuids = AssetDatabase.FindAssets("t:prefab", new[] { "Assets/Arts/World/sandtable/pointModlue/" });
            string[] resmodelGuidss = AssetDatabase.FindAssets("t:prefab", new[] { "Assets/Arts/World/sandtable/pointModlue4/" }); // 资源点装饰物模组路径
            System.Random random = new System.Random();
            //
            for (int i = 0; i < _pointRoot.transform.childCount; i++)
            {
                Transform pointTf = _pointRoot.transform.GetChild(i);
                int.TryParse(pointTf.name, out int pointType);
                if (pointType == (int)WorldEntry.MapPointType.E_EditorResPoint)
                {
                    if (resmodelGuidss.Length > 0)
                    {
                        int idx = random.Next(0, resmodelGuidss.Length);
                        string guid = resmodelGuidss[idx];
                        string assetPath = AssetDatabase.GUIDToAssetPath(guid);
                        GameObject model = AssetDatabase.LoadAssetAtPath<GameObject>(assetPath);
                        model = PrefabUtility.InstantiatePrefab(model, _pointAdornRootScript.transform) as GameObject;
                        model.name = "MODOL<" + assetPath + ">";
                        PointAdornModel adornScript = model.GetOrAddComponent<PointAdornModel>();
                        adornScript.BindPoint(pointTf.gameObject);
                    }
                }
                else{
                    if (modelGuids.Length > 0)
                    {
                        int idx = random.Next(0, modelGuids.Length);
                        string guid = modelGuids[idx];
                        string assetPath = AssetDatabase.GUIDToAssetPath(guid);
                        GameObject model = AssetDatabase.LoadAssetAtPath<GameObject>(assetPath);
                        model = PrefabUtility.InstantiatePrefab(model, _pointAdornRootScript.transform) as GameObject;
                        model.name = "MODOL<" + assetPath + ">";
                        PointAdornModel adornScript = model.GetOrAddComponent<PointAdornModel>();
                        adornScript.BindPoint(pointTf.gameObject);
                    }
                }
            
            }
  
            if (_pointAdornRootScript)
            {
                _pointAdornRootScript.FindAdorn();
            }
        }

        void LoadChunckPointData4()
        {
            CreatePointRoot();
            // 删除所有二级装饰物
            if (_pointAdornRootScript)
            {
                _pointAdornRootScript.FindAdorn();
                List<PointAdorn> adorns = _pointAdornRootScript.GetAdorns();
                for (int i = 0; i < adorns.Count; i++)
                {
                    PointAdorn adorn = adorns[i];
                    if (adorn.type >= 5 && adorn.type <= 8)
                    {
                        GameObject.DestroyImmediate(adorn.gameObject);
                    }
                }
                _pointAdornRootScript.FindAdorn();
            }
            Dictionary<string, bool> connectRecord = new Dictionary<string, bool>();
            for (int i = 0; i < _pointRoot.transform.childCount; i++)
            {
                Transform tf = _pointRoot.transform.GetChild(i);
                for (int ii = 0; ii < _pointRoot.transform.childCount; ii++)
                {
                    Transform tf1 = _pointRoot.transform.GetChild(ii);
                    if (tf.gameObject.name == "3_测试" && tf1.gameObject.name == "3_测试")
                    {
                        int a = 0;
                    }
                    int idx = tf.GetSiblingIndex();
                    int idx1 = tf1.GetSiblingIndex();
                    if (idx != idx1)
                    {
                        int type = ChenckAdornLevel2(tf.position, tf1.position);
                        bool isAdd = connectRecord.ContainsKey(idx + "_" + idx1) || connectRecord.ContainsKey(idx1 + "_" + idx);
                        if (type > 0 && !isAdd)
                        {
                            connectRecord[idx + "_" + idx1] = true;
                            // 创建空二级装饰物
                            GameObject obj = new GameObject();
                            obj.transform.parent = _pointAdornRootScript.transform;
                            PointAdorn adorn = obj.AddComponent<PointAdorn>();
       
                            adorn.AddObjs(tf.gameObject);
                            adorn.AddObjs(tf1.gameObject);
                            adorn.type = -1;
                            adorn.CheckPoints(type);
                            adorn.prefabPathIdx = 0;
                            adorn.UpdatePrefab("0类型连接出生点装饰物");
                        }
                    }
                }
            }
        }

        int ChenckAdornLevel2(Vector3 pos, Vector3 pos1)
        {
            int type = -1;
            if (pos.x == pos1.x)
            {
                float dis = (pos1.z - pos.z);
                float dis1 = Mathf.Abs(dis) - 2;
                if (dis1 < 0.00001)
                {
                    if (dis > 0)
                    {
                        type = 5;
                    }
                    else
                    {
                        type = 7;
                    }
                }
            }
            else if (pos.z == pos1.z)
            {
                float dis = (pos1.x - pos.x);
                float dis1 = Mathf.Abs(dis) - 2;
                if (dis1 < 0.00001)
                {
                    if (dis > 0)
                    {
                        type = 6;
                    }
                    else 
                    {
                        type = 8;
                    }
                }
            }
            return type;
        }

        #endregion
    }
}
